検索
ホームページJava&#&チュートリアルJava関数型プログラミングのサンプル分析

この「Java 関数プログラミング例の分析」記事の知識ポイントを理解していない人がほとんどであるため、編集者はすべての人のために次の内容を要約しました。内容は詳細で、手順は明確で、実用的な重要性を持っていますので、参考までに、この記事を読んで何かを得ていただければ幸いです。「Java 関数プログラミングのサンプル分析」の記事を見てみましょう。

1. ラムダ式

1.1 関数プログラミングの考え方の概要

数学では、関数とは入力量と出力量を含む一連の計算スキームです。 、「データを操作する」

オブジェクト指向の思考は、「物事はオブジェクトの形式で行われなければならない」ことを強調します

関数型の思考は、Jinliang がオブジェクト指向の複雑なステートメントを無視することを強調します。 「どうやって行うかではなく、何を行うかを強調する」要件:

スレッドを開始し、コンソールに文を出力します: マルチスレッド プログラムの開始

方法 1:

定義 A class MyRunnable インターフェイス、run メソッドをオーバーライドする

MyRunnable クラスのオブジェクトを作成する
  • Thread クラス オブジェクトを作成し、MyRunnable オブジェクトを使用する構築パラメーターとして渡す
  • Start thread
  • public class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("多线程程序启动了");
        }
    }
            MyRunnable myRunnable = new MyRunnable();
            Thread thread = new Thread(myRunnable);
            thread.start();

  • メソッド 2:
  • メソッドに基づく1 改善、匿名内部クラスを使用する方法
  •       new Thread(new Runnable() {
               @Override
                public void run() {
                    System.out.println("多线程程序启动了");
                }
            }).start();

方法 3:

ラムダ式の改善方法:

        new Thread(() -> {
            System.out.println("多线程程序启动了");
        }).start();
1.3 ラムダ式の標準形式

匿名内部クラスの run() メソッドをオーバーライドするコード分析:

メソッドの仮パラメータが空です、メソッドを呼び出すときにパラメータを渡す必要がないことを示します

メソッドの戻り値の型は void で、メソッドの実行時に結果が返されないことを示します
    メソッド本体の
  • 内容は具体的に行う必要がある内容です。
  •       new Thread(new Runnable() {
               @Override
                public void run() {
                    System.out.println("多线程程序启动了");
                }
            }).start();

  • ラムダ式のコード分析:

# (): 内容がありません。メソッドの仮パラメータが空であると見なされます

  • # #->:

    矢印を使用して、後で実行することを示します

  • {}:

    には、次のコードが含まれています。メソッド本体のコンテンツとみなすことができるコード ブロック

            new Thread(() -> {
                System.out.println("多线程程序启动了");
            }).start();
  • ラムダ式を構成する 3 つの要素: 仮パラメータ、矢印、コード ブロック
  • ラムダ式の形式:

形式:

(仮パラメータ) ->{コード ブロック}

  • 仮パラメータ:

    複数のパラメータがある場合は、カンマで区切ってください。パラメータがない場合は、空白のままにしてください。

  • # #->:
  • は英語の下線と大なり記号で構成され、固定された書き方になります。ポインティング アクションを表します。

  • コード ブロック:
  • は、具体的に実行する必要があるもので、前に作成したメソッド本体の内容です。

    1.4 ラムダ式の演習
  • ラムダ式を使用するための前提条件

    インターフェイスがあります

インターフェイス 抽象メソッドは 1 つだけです。

  • 演習 1:

  • インターフェイス (Eatable) を定義します。抽象メソッドを定義します: void Eat();

テスト クラス (EatableDemo) を定義し、テスト クラスに 2 つのメソッドを提供します:

  • 1 つのメソッドは次のとおりです:

    useEatable(Eatable e)

  • 1 つのメソッドがメイン メソッドであり、useEatable メソッドが呼び出されます。メイン メソッド
    • インターフェイスを定義します:
    • public interface Eatable {
          void eat();
      }

      メソッド 1:
    • 従来のインターフェイス実装クラス
    public class EatableImpl implements Eatable{
        @Override
        public void eat() {
            System.out.println("一日三餐,必不可少");
        }
    }
    public class EatableDemo{
        public static void main(String[] args) {
            Eatable eatable = new EatableImpl();
            eatable.eat();
        }
    
        private static void useEatable(Eatable eatable){
            eatable.eat();
        }
    }

方法 2: 匿名内部クラス

public class EatableDemo{
    public static void main(String[] args) {
        useEatable(new Eatable() {
            @Override
            public void eat() {
                System.out.println("一日三餐,必不可少");
            }
        });
    }
    private static void useEatable(Eatable eatable){
        eatable.eat();
    }
}

方法 3: ラムダ式

public class EatableDemo{
    public static void main(String[] args) {
        useEatable(()->{
            System.out.println("一日三餐,必不可少");
        });
    }
    private static void useEatable(Eatable eatable){
        eatable.eat();
    }
}

実行結果は同じ

演習 2:

抽象メソッドを定義するインターフェイス (Flyable) を定義します: void fiy(String s);

テスト クラス (FlyableDemo) を定義し、テスト クラスに 2 つのメソッドを提供します。

  • 1 つのメソッドは次のとおりです。
  • useFlyable(Flyable f)
  • 1 つのメソッドがメイン メソッドであり、useFlayable メソッドがメイン メソッドで呼び出されます
    • public interface Flyable {
          void fly(String s);
      }
      rrree

      演習 3:
    • 抽象メソッドを定義するインターフェイス (Addable) を定義します: int add(int x, int y);

テスト クラス (AddableDemo) を定義し、テスト クラスに 2 つのメソッドを提供します。

  • 1 つのメソッドは次のとおりです:
  • useAddable(Addable a)
  • 1 つのメソッドがメイン メソッドであり、メイン メソッドで useAddable メソッドが呼び出されます。
    • public class FlyableDemo {
          public static void main(String[] args) {
      
              useFlyable(new Flyable() {
                  @Override
                  public void fly(String s) {
                      System.out.println(s);
                      System.out.println("飞机可以起飞");
                  }
              });
              System.out.println("--------------------");
              useFlyable((String s)->{
                  System.out.println(s);
                  System.out.println("飞机可以起飞");
              });
          }
          private static void useFlyable(Flyable flyable){
              flyable.fly("风和日丽,晴空万里");
          }
      }
      public interface Addable {
          int add(int x,int y);
      }
      1.5 ラムダ式の省略モード

    • 省略規則:

    #パラメータの型は省略可能です。パラメータが複数ある場合、
を 1 つだけ省略することはできません。
  • 如果参数有且仅有一个,那么小括号可以省略

  • 如果代码块的语句只有一条,可以省略大括号和分号,甚至时return

  • public class LambdaDemo5 {
        public static void main(String[] args) {
            //参数类型可以省略
            useAddable((x, y) -> {
                return x + y;
            });
            System.out.println("------------------------");
            //如果只有一个参数,小括号也可以省略
            useFlyable(s -> {
                System.out.println(s);
            });
            System.out.println("------------------------");
            //如果代码块的语句只有一条,可以省略大括号和分号(有return时要把return也去掉)
            useFlyable(s ->
                System.out.println(s)
            );
            useAddable((x,y)->x+y);
        }
        private static void useFlyable(Flyable flyable) {
            flyable.fly("风和日丽,晴空万里");
        }
        private static void useAddable(Addable addable) {
            int sum = addable.add(10, 20);
            System.out.println(sum);
        }
    }

    接口类参考1.4

    1.6 Lambda表达式的注意事项

    注意事项:

    • 使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象的方法

    • 必须有上下文环境,才能推导出Lambda对应的接口

      • 根据局部变量的赋值得知Lambda对应的接口:Runnable r =() ->System.out.println(“Lambda表达式”);

      • 根据调用方法的参数得知Lambda对应的接口:new Thread(()->System.out.println(“Lambda表达式”)).start();

    public interface Inter {
        void show();
    }
    public class LambdaDemo6 {
        public static void main(String[] args) {
            useInter(()->
                    System.out.println("Lambda表达式")
            );
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("匿名内部类");
                }
            }).start();
            Runnable r = () -> System.out.println("Lambda表达式");
            new Thread(r).start();
    
            new Thread(()->
                System.out.println("Lambda表达式")
            ).start();
        }
        private static void useInter(Inter inter){
            inter.show();
        }
    }

    1.7 Lambda表达式和匿名内部类的区别

    所需类型不同:

    • 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类

    • Lambda表达式:只能是接口

    使用限制不同:

    • 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类

    • 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式

    实现原理不同:

    • 匿名内部类:编译之后,产生一个单独的.class字节码文件

    • Lambda表达式:编译之后,没有一个单独的.class字节码文件,对应的字节码会在运行的时候动态生成

    二、接口组成更新

    1.1 接口组成更新概述

    接口的组成:

    • 常量:public static final

    • 抽象方法:public abstract

    • 默认方法(Java 8)

    • 静态方法(Java 8)

    • 私有方法 (Java 8)

    1.2 接口中默认方法

    接口中默认方法得定义格式:

    • 格式:public default 返回值类型 方法名(参数列表){}

    • 范例:public default void show3(){}

    接口中默认方法的注意事项:

    • 默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字

    • public可以省略,default不能重写

    public interface MyInterface {
        void show1();
    
        void show2();
    
        default void show3(){
            System.out.println("show3");
        }
    }
    public class MyInterfaceImplOne implements MyInterface{
        @Override
        public void show1() {
            System.out.println("One show1");
        }
    
        @Override
        public void show2() {
            System.out.println("One show2");
        }
    }
    public class MyInterfaceImplTwo implements MyInterface{
        @Override
        public void show1() {
            System.out.println("Two show1");
        }
    
        @Override
        public void show2() {
            System.out.println("Two show2");
        }
    }
    public class InterfaceDemo {
        public static void main(String[] args) {
            MyInterface myInterface = new MyInterfaceImplOne();
            myInterface.show1();
            myInterface.show2();
            myInterface.show3();
            System.out.println("------------------");
            MyInterface myInterface2 = new MyInterfaceImplTwo();
            myInterface2.show1();
            myInterface2.show2();
            myInterface2.show3();
        }
    }

    运行结果:

    One show1
    One show2
    show3
    ------------------
    Two show1
    Two show2
    show3

    1.3 接口中静态方法

    接口中静态方法的定义格式:

    • 格式:public static 返回值类型 方法名(参数列表){ }

    • 范例:public static void show(){ }

    接口中静态方法的注意事项:

    • 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用

    • public可以省略,static不能省略

    public interface Inter {
        void show();
        default void method() {
            System.out.println("Inter 中的默认方法执行了");
        }
        public static void test(){
            System.out.println("Inter 中的静态方法执行了");
        }
    }
    public class InterImpl implements Inter{
        @Override
        public void show() {
            System.out.println("show方法执行了");
        }
    }
    public class InterDemo {                                           
        public static void main(String[] args) {                       
            Inter inter = new InterImpl();                             
            inter.show();                                             
            inter.method();                                           
            Inter.test();                                             
        }                                                             
    }

    1.4 接口中私有方法

    Java 9中新增了带方法体的私有方法,这其实在Java 8中就埋下了伏笔:Java 8允许在接口中定义带方法体的默认方法和静态方法。这样可能就会引发一个问题:当两个默认方法或者静态方法中包含一段相同的代码实现时,程序必然考虑将这段实现代码抽取成一个共性方法,而这个共性方法时不需要让别人使用的,因此用私有给隐藏起来,这就是Java 9增加私有方法的必然性。

    接口中私有方法的定义格式:

    • 格式1:private 返回值类型方法名(参数列表){ }

    • 范例1:private void show(){ }

    • 格式2:private static 返回值类型 方法名(参数列表){ }

    • 范例2:private static void method(){ }

    接口中私有方法的注意事项:

    • 默认方法可以调用私有的静态方法和非静态方法

    • 静态方法只能调用私有的静态方法

    public interface Inter {
        default void show1(){
            System.out.println("show1开始执行");
            method();
            System.out.println("show1结束执行");
        }
        default void show2(){
            System.out.println("show2开始执行");
            method();
            System.out.println("show2结束执行");
        }
        static void method1(){
            System.out.println("method1开始执行");
            method();
            System.out.println("method1结束执行");
        }
        static void method2(){
            System.out.println("method2开始执行");
            method();
            System.out.println("method2结束执行");
        }
        static void method(){
            System.out.println("初级工程师");
            System.out.println("中级工程师");
            System.out.println("高级工程师");
        }
    }
    public class InterImpl implements Inter{
    }
    public class InterDemo {
        public static void main(String[] args) {
            Inter inter = new InterImpl();
            inter.show1();
            System.out.println("------------------------");
            inter.show2();
            System.out.println("------------------------");
            Inter.method1();
            System.out.println("------------------------");
            Inter.method2();
        }
    }

    三、方法引用

    1.1 体验方法引用

    通过方法引用来使用已经存在的方案

    public interface Printable {
        void printString(String s);
    }
    public class PrintableDemo {
        public static void main(String[] args) {
            usePrintable(s->
                System.out.println(s)
            );
    
            usePrintable(System.out::println);
        }
        private static void usePrintable(Printable p){
            p.printString("hello world");
        }
    }

    1.2 方法引用符

    • ::该符号为引用运算符,而它所在表达式被称为方法引用符

    • Lambda表达式:usePrintable(s->System.out.println(s));

    分析:拿到参数s之后通过Lambda表达式,传递给System.out.println方法去处理

    • 方法引用:usePrintable(System.out::println);

    分析:直接使用System.out中的println方法来取代Lambda,代码更加的简洁

    推导与省略:

    • 如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导

    • 如果使用方法引用,也同要可以根据上下文进行推导

    • 方法引用是Lambda的孪生兄弟

    public interface Printable {
        void printInt(int i);
    }
    public class PrintableDemo2 {
        public static void main(String[] args) {
            usePrintable(i -> System.out.println(i));
    
            usePrintable(System.out::println);
        }
        private static void usePrintable(Printable printable){
            printable.printInt(1);
        }
    }

    1.3 Lambda表达式支持的方法引用

    常见的引用方式:

    • 引用类方法

    • 引用对象的实例方法

    • 引用类的实例方法

    • 引用构造器

    1.4 引用类方法

    引用类方法,其实就是引用类的静态方法

    • 格式:类名::静态方法

    • 范例:Integer::parseInt

      • Integer类的方法:public static int parsenInt(String s),将此String转换为int类型数据

      • Lambda表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数

    public interface Converter {
        int convert(String s);
    }
    public class ConverterDemo {
        public static void main(String[] args) {
            useConverter(s -> Integer.parseInt(s));
            useConverter(Integer::parseInt);
        }
        private static void useConverter(Converter c) {
            int number = c.convert("666");
            System.out.println(number);
        }
    }

    1.5 引用对象的实例方法

    引用对象的实例方法,其实就是引用类中的成员方法

    • 格式:对象::成员方法

    • 范例:“HelloWorld"::toUpperCase

    • String 类中的方法:public String toUpperCase()将此String所有字符转为大写

    • Lambda表达式被对象的实例方法替代的时候,它的形式参数全部传递给该方法作为参数

    public interface Printer {
        void printUpperCase(String s);
    }
    public class PrintString {
        public void printUpper(String s){
            String result = s.toUpperCase();
            System.out.println(result);
        }
    }
    public class PrinterDemo {
        public static void main(String[] args) {
            usePrinter(s -> System.out.println(s.toUpperCase()));
    
            PrintString printString = new PrintString();
            usePrinter(printString::printUpper);
        }
        private static void usePrinter(Printer printer) {
            printer.printUpperCase("HelloWorld");
        }
    }

    1.6 引用类的实例方法

    引用类的实例方法,其实就是引用类中的成员方法

    • 格式:类名::成员方法

    • 范例:String::substring

    • String类中的方法:public String subString(int beginIndex,int endIndex)从beginIndex开始到endIndex结束,截取字符串。返回一个子串,字串的长度为endIndex-beginIndex

    • Lambda表达式被类的实例方法替代的时候,第一个参数作为调用者,后面的参数全部传递给该方法作为参数

    public interface MyString {
        String mySubString(String s, int x, int y);
    }
    public class MyStringDemo {
        public static void main(String[] args) {
            useMyString((s, x, y) -> s.substring(x, y));
    
            useMyString(String::substring);
        }
        private static void useMyString(MyString myString){
            String s = myString.mySubString("HelloWorld", 5, 10);
            System.out.println(s);
        }
    }

    1.7 引用构造器

    引用构造器,其实就是引用构造方法

    • 格式:类名::new

    • 范例:Student::new

    • Lambda表达式被构造器代替的时候,它的形式参数全部传递给构造器作为参数

    public class Student {
        private String name;
        private int age;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public Student() {
        }
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    public interface StudentBuilder {
        Student build(String name,int age);
    }
    public class StudentDemo {
        public static void main(String[] args) {
            useStudentBuilder((name, age) -> new Student(name,age));
    
            useStudentBuilder(Student::new);
        }
    
        private static void useStudentBuilder(StudentBuilder studentBuilder){
            Student student = studentBuilder.build("xuanxuan", 22);
            System.out.println(student.getName()+","+student.getAge());
        }
    }

    四、函数式接口

    1.1 函数接口概述

    函数式接口:有且仅有一个抽象方法的接口

    Java中的函数式编程体现就是Lambda表达式,所以函数式接口就是可以使用于Lambda使用的接口

    只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导

    如何检测一个接口是不是函数式接口呢?

    • @FunctionalInterface

    • 放在接口定义的上方:如果接口是函数接口,编译通过;如果不是,编译失败

    注意:

    我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我们不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上注解。

    @FunctionalInterface
    public interface MyInterface {
        void show();
    }
    public class MyInterfaceDemo {
        public static void main(String[] args) {
            MyInterface myInterface = ()-> System.out.println("函数式接口");
            myInterface.show();
        }
    }

    1.2 函数式接口作为方法的参数

    如果方法的参数是一个函数式接口,我们可以使用Lambda表达式作为参数传递

    startThread(() -> System.out.println(Thread.currentThread().getName() + "线程启动了"));
    public class RunnableDemo {
        public static void main(String[] args) {
            startThread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "线程启动了");
                }
            });
    
            startThread(() -> System.out.println(Thread.currentThread().getName() + "线程启动了"));
    
            startThread(()->{
                System.out.println(Thread.currentThread().getName() + "线程启动了");
            });
        }
        private static void startThread(Runnable runnable) {
            new Thread(runnable).start();
        }
    }

    1.3 函数式接口作为方法的返回值

    如果方法的返回值是一个函数式接口,我们可以使用Lambda表达式作为结果返回

    private static Comparator<String> getComparator() {
            return (s1,s2) -> s1.length() - s2.length();
        }
    public class ComparatorDemo {
        public static void main(String[] args) {
            ArrayList<String> arrayList = new ArrayList<String>();
    
            arrayList.add("ccc");
            arrayList.add("aa");
            arrayList.add("dddd");
            arrayList.add("b");
            System.out.println("排序前" + arrayList);
            Collections.sort(arrayList);
            System.out.println("排序后" + arrayList);
            Collections.sort(arrayList, getComparator());
            System.out.println("使用定义比较器排序方法后:" + arrayList);
        }
    
        private static Comparator<String> getComparator() {
    //        return new Comparator<String>() {
    //            @Override
    //            public int compare(String s1, String s2) {
    //                return s1.length() - s2.length();
    //            }
    //        };
            return (s1,s2) -> s1.length() - s2.length();
        }
    }

    1.4 常用的函数式接口

    Java 8 在java.util.function包下预定了大量的函数式接口供我们使用,常用如下:

    • Supplier接口

    • Consumer接口

    • Predicate接口

    • Function接口

    1.5 Supplier接口

    Supplier接口

    • T get():获得结果

    • 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据

    • Supplier 接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用

    public class SupplierDemo {
        public static void main(String[] args) {
            String s = getString(() -> "xuanxuan");
            System.out.println(s);
    
            Integer i = getInteger(() -> 666);
            System.out.println(i);
        }
    
        public static String getString(Supplier<String> supplier) {
            return supplier.get();
        }
        public static Integer getInteger(Supplier<Integer> supplier) {
            return supplier.get();
        }
    }

    练习:获取最大值

    public class SupplierDemo {
        public static void main(String[] args) {
            int[] arr = new int[]{17, 28, 49, 21, 32, 66};
            int maxNumber = getMax(() -> {
                int max = arr[0];
                for (int i = 1; i < arr.length; i++) {
                    if (max < arr[i]) {
                        max = arr[i];
                    }
                }
                return max;
            });
            System.out.println("数组中的最大值是:" + maxNumber);
        }
    
        private static int getMax(Supplier<Integer> supplier) {
            return supplier.get();
        }
    }

    1.6 Consumer接口

    Consumer:包含两个方法

    • void accept(T t):对给定的参数执行此操作

    • default Consumer andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作

    • Consumer 接口也被称为消费型接口,它消费的数据类型由泛型指定

    public class ConsumerDemo {
        public static void main(String[] args) {
            operatorString("abc", s -> System.out.println(s));
            operatorString("abc", System.out::println);
            operatorString("abc", s -> System.out.println(new StringBuilder(s).reverse().toString()));
            System.out.println("----------------------------------");
            operatorString("abc", s -> System.out.println(s), s -> System.out.println(new StringBuilder(s).reverse().toString()));
        }
    
        private static void operatorString(String name, Consumer<String> consumer) {
            consumer.accept(name);
        }
    
        private static void operatorString(String name, Consumer<String> consumer1, Consumer<String> consumer2) {
    //        consumer1.accept(name);
    //        consumer2.accept(name);
            consumer1.andThen(consumer2).accept(name);
        }
    }

    练习:

    字符串数组中又多条信息,按照:“姓名:name,年龄:age"的格式将信息打印出来

    public class ConsumerDemo {
        public static void main(String[] args) {
            String[] arr = new String[]{"abc,30", "cbd,35", "dna,33"};
            printInfo(arr, s -> System.out.print("姓名:" + s.split(",")[0] + ","), s -> System.out.println("年龄:" + Integer.parseInt(s.split(",")[1])));
        }
    
        private static void printInfo(String[] arr, Consumer<String> consumer1, Consumer<String> consumer2) {
            for (String s : arr) {
                consumer1.andThen(consumer2).accept(s);
            }
        }
    }

    1.7 Predicate接口

    常用方法:

    Java関数型プログラミングのサンプル分析

    练习:判断给定的字符串是否满足要求

    public class PredicateDemo {
        public static void main(String[] args) {
            boolean b1 = checkString("hello", s -> s.length() > 5);
            System.out.println(b1);
    
            boolean b2 = checkString("helloworld", s -> s.length() > 8);
            System.out.println(b2);
    
            boolean b3 = checkString("hello", s -> s.length() > 5, s -> s.length() > 8);
            System.out.println(b3);
    
            boolean b4 = checkString("helloworld", s -> s.length() > 5, s -> s.length() > 8);
            System.out.println(b4);
        }
    
        private static boolean checkString(String s, Predicate<String> predicate) {
            return predicate.test(s);
        }
    
        private static boolean checkString(String s, Predicate<String> predicate, Predicate<String> predicate2) {
    //        return predicate.and(predicate2).test(s);
            return predicate.or(predicate2).test(s);
        }
    }

    练习2:

    • String[] strArray ={“孙悟空,30”,“唐僧,36”,“沙僧,34”,“猪八戒,32”,“白骨精,5000”}

    • 字符串数组中有多条信息,请通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayLitst中,并遍历ArrayLitst集合

    • 同时满足如下要求:name长度大于2,age大于33

    public class PredicateDemo3 {
        public static void main(String[] args) {
            String[] strArray = new String[]{"孙悟空,30", "唐僧,36", "沙僧,34", "猪八戒,32", "白骨精,5000"};
            ArrayList<String> arrayList = myFilter(strArray, s -> s.split(",")[0].length() > 2, s -> Integer.parseInt(s.split(",")[1]) > 33);
            System.out.println("name长度大于2,age大于33有:");
            for (String s : arrayList) {
                System.out.print("name:" + s.split(",")[0] + ",");
                System.out.println("age:" + Integer.parseInt(s.split(",")[1]));
            }
        }
    
        private static ArrayList<String> myFilter(String[] strArray, Predicate<String> predicate1, Predicate<String> predicate2) {
            ArrayList<String> arrayList = new ArrayList<String>();
            for (String s : strArray) {
                if (predicate1.and(predicate2).test(s)) {
                    arrayList.add(s);
                }
            }
            return arrayList;
        }
    }

    1.8 Function接口

    Function两个常用方法:

    Java関数型プログラミングのサンプル分析

    Function接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现)然后返回一个新的值

    练习:

    public class FunctionDemo {
        public static void main(String[] args) {
            convert("100", s -> Integer.parseInt(s));
            convert("100", Integer::parseInt);
    
            convert(100, i -> String.valueOf(100 + i));
    
            convert("100", s -> Integer.parseInt(s), i -> String.valueOf(i + 566));
    
        }
        //定义一个方法,把一个int类型的数据加上一个整数之后,转为字符串在控制台输出
        private static void convert(String s, Function<String, Integer> function) {
            Integer i = function.apply(s);
            System.out.println(i);
        }
        //定义一个方法,把一个int类型的数据加上一个整数之后,转为字符串在控制台输出
        private static void convert(int i, Function<Integer, String> function) {
            String s = function.apply(i);
            System.out.println(s);
        }
        //定义一个方法,把一个字符串转换为int类型,把int类型的数据加上一个整数之后,转为字符串在控制台输出
        private static void convert(String s, Function<String, Integer> function1, Function<Integer, String> function2) {
            String ss = function2.apply(function1.apply(s));
            System.out.println(ss);
        }
    }

    练习2:提取String中的年龄加70岁,并以int型输出

    public class FunctionDemo {
        public static void main(String[] args) {
            String s = "孙悟空,30";
            convert(s, s1 -> s1.split(",")[1], s1 -> Integer.parseInt(s1) + 70);
        }
    
        private static void convert(String s, Function<String, String> function1, Function<String, Integer> function2) {
            Integer i = function2.apply(function1.apply(s));
            System.out.println(i);
        }
    }

    五、Stream流

    1.1 体验Stream流

    需求:按照下面的要求完成集合的创建和遍历

    • 创建一个集合,存储多个字符串元素

    • 把集合中所有以“张”开头的元素存储到一个新的集合再

    • 把长度为3的元素存储到一个新集合

    • 最后遍历上一步得到的集合

    使用Stream流的方式完成过滤操作:

    • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:生成流、过滤姓氏、过滤长度为3、逐一打印

    • Stream流把真正的函数式编程风格引入到java中

    list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
    public class StreamDemo {
        public static void main(String[] args) {
            ArrayList list = new ArrayList();
            list.add("张飞");
            list.add("张三丰");
            list.add("张三");
            list.add("李四");
            list.add("孙悟空");
            list.add("张一飞");
    
            ArrayList zhangList = new ArrayList();
            for (String s : list) {
                if (s.startsWith("张")) {
                    zhangList.add(s);
                }
            }
            ArrayList treeList = new ArrayList();
            for (String s : zhangList) {
                if (s.length() == 3) {
                    treeList.add(s);
                }
            }
            for (String s : treeList) {
                System.out.println(s);
            }
            System.out.println("-------------------------------");
            //Stream流改进
            list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
        }
    }

    1.2 Stream流的生成方式

    Stream流的使用

    生成流:通过数据源(集合、数组等)生成流

    list.stream();

    中间操作:一个流后面可以跟随零个或者多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用

    filter()

    终结操作:一个流只能有一个终结操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作

    forEach()

    Stream流的常见生成方式

    Collection体系的集合可以使用默认方法stream()生成流

    default Stream<E> stream()
    • Map体系的集合间接的生成流

    • 数组可以通过Stream接口的静态方法of(T…values)生成流

    public class StreamDemo {
        public static void main(String[] args) {
            List<String> list = new ArrayList<String>();
            Stream<String> listStream = list.stream();
    
            Set<String> set = new HashSet<String>();
            Stream<String> setStream = set.stream();
    
            Map<String, Integer> map = new HashMap<String, Integer>();
            Stream<String> keyStream = map.keySet().stream();
            Stream<Integer> valueStream = map.values().stream();
            Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
    
            String[] strArray = {"hello", "world", "java"};
            Stream<String> strArrayStream = Stream.of(strArray);
            Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
            Stream<Integer> strArrayStream3 = Stream.of(10, 20, 30);
        }
    }

    1.3 Stream流的常见中间操作方法

    • Stream filter(Predicate predicate):用于对流中的数据进行过滤

    • Predicate接口中的方法:boolean test(T t):对给定的参数进行判断,返回一个布尔值

    public class StreamDemo {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<String>();
            list.add("张飞");
            list.add("张三丰");
            list.add("张三");
            list.add("李四");
            list.add("孙悟空");
            list.add("张一飞");
            list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
            System.out.println("----------------------");
            list.stream().filter(s -> s.length() == 3).forEach(System.out::println);
            System.out.println("----------------------");
            list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
        }
    }
    • Stream limit(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据

    • Stream skip(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流

    public class StreamDemo {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<String>();
            list.add("张飞");
            list.add("张三丰");
            list.add("张三");
            list.add("李四");
            list.add("孙悟空");
            list.add("张一飞");
            //取前三个数据在控制台输出
            list.stream().limit(3).forEach(System.out::println);
            System.out.println("-----------------------------");
            //跳过2个元素,把剩下的元素在控制台上输出
            list.stream().skip(2).forEach(System.out::println);
            System.out.println("-----------------------------");
            //跳过2个元素并将剩下元素的前两个元素在控制台上输出
            list.stream().skip(2).limit(2).forEach(System.out::println);
        }
    }
    • Stream Stream concat(Stream a,Stream b):合并a和b两个流为一个流

    • Stream distinct:返回由该流的不同元素(根据Objectequals(Object))组成的流

    public class StreamDemo {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<String>();
            list.add("张飞");
            list.add("张三丰");
            list.add("张三");
            list.add("李四");
            list.add("孙悟空");
            list.add("张一飞");
            //需求1:取前4个数据组成一个流
            Stream<String> limitStream = list.stream().limit(4);
            //需求2:跳过2个数据组成一个流
            Stream<String> skipStream = list.stream().skip(2);
            //需求3:合并需求1和需求2得到的流,并把结果在控制台输出
    //        Stream.concat(limitStream,skipStream).forEach(System.out::println);
            //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
            Stream.concat(limitStream,skipStream).distinct().forEach(System.out::println);
        }
    }
    • Stream sorted():返回由此流的元素组成的流,根据自然顺序排序

    • Stream sorted(Comparator comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序

    public class StreamDemo {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<String>();
            list.add("zhangfei");
            list.add("zhangsanfeng");
            list.add("zhangsan");
            list.add("lisi");
            list.add("sunwukong");
            list.add("zhangyifei");
    
            //需求1:按照字母顺序把数据在控制台输出
            list.stream().sorted().forEach(System.out::println);
            //需求2:按照字符串长度把数据在控制台输出
            list.stream().sorted((s1, s2) -> {
                int num = s1.length() - s2.length();
                int num2 = num == 0 ? s1.compareTo(s2) : num;
                return num2;
            }).forEach(System.out::println);
        }
    }
    • Stream map(Function mapper):返回由给定函数应用于此流的元素的结果组成的流(Function接口中的方法 R apply(T t))

    • IntStream mapToInt(ToIntFunction mapper):返回一个IntStream其中包含将给定函数应用于此流的元素的结果

    public class StreamDemo {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<String>();
            list.add("10");
            list.add("20");
            list.add("30");
            list.add("40");
            list.add("50");
    
    //        list.stream().map(s -> Integer.parseInt(s)).forEach(System.out::println);
            list.stream().map(Integer::parseInt).forEach(System.out::println);
    
            list.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
    
            int result = list.stream().mapToInt(Integer::parseInt).sum();
            System.out.println(result);
        }
    }

    1.4 Stream流的常见终结操作方法

    • void forEach(Consumer action):对此流的每个元素执行操作(Consumer接口中的方法 void accept(T t):对给定的参数执行此操作)

    • long count():返回此流中的元素数

    public class StreamDemo {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<String>();
            list.add("张飞");
            list.add("张三丰");
            list.add("张三");
            list.add("李四");
            list.add("孙悟空");
            list.add("张一飞");
    
            //需求1:把集合中的元素在控制台输出
            list.stream().forEach(System.out::println);
    
            //需求2:统计集合中有几个姓张的元素并在控制台输出
            list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
        }
    }

    1.5 Stream流的练习

    现在又两个ArrayList集合,分别存储6名男演员和6名女演员名称,要求完成如下操作

    • 男演员只要名字为3个字的前三人

    • 女演员只要姓林的,并且不要第一个

    • 把过滤后的男演员姓名和女演员姓名合并到一起

    • 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据(演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法)

    public class StreamDemo {
        public static void main(String[] args) {
            ArrayList<String> manList = new ArrayList<String>();
            manList.add("周润发");
            manList.add("成龙");
            manList.add("刘德华");
            manList.add("吴京");
            manList.add("周星驰");
            manList.add("李连杰");
            ArrayList<String> womanList = new ArrayList<String>();
            womanList.add("林心如");
            womanList.add("张曼玉");
            womanList.add("林青霞");
            womanList.add("柳岩");
            womanList.add("林志玲");
            womanList.add("王祖贤");
    
            //男演员只要名字为3个字的前三人
            Stream<String> manStream = manList.stream().filter(s -> s.length() == 3).limit(3);
    
            //女演员只要姓林的,并且不要第一个
            Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);
    
            //把过滤后的男演员姓名和女演员姓名合并到一起
            Stream<String> stream = Stream.concat(manStream, womanStream);
    
            //把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
            stream.map(Actor::new).forEach(p -> System.out.println(p.getName()));
            System.out.println("------------------------------------");
            //改进
            Stream.concat(manList.stream().filter(s -> s.length() == 3).limit(3), womanList.stream().filter(s -> s.startsWith("林")).skip(1)).map(Actor::new).forEach(p -> System.out.println(p.getName()));
        }
    }

    1.6 Stream流的收集操作

    对数据使用Stream流的方式操作完毕后,如何把流中的数据收集到集合中?

    Stream流的手机方法

    • R collect(Collector collector)

    • 但是这个收集方法的参数是一个Collector接口

    工具类Collectors提供了具体的收集方式:

    • public static Collector toList():把元素收到List集合中

    • public static Collector toSet():把元素收集到Set集合中

    • public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中

    public class StreamDemo {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<String>();
            list.add("张飞");
            list.add("张三丰");
            list.add("张三");
            list.add("李四");
            list.add("孙悟空");
            list.add("张一飞");
    
            //需求1:得到名字为3个字的流
            Stream<String> listStream = list.stream().filter(s -> s.length() == 3);
            //需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历
            List<String> collect = listStream.collect(Collectors.toList());
            for (String s : collect) {
                System.out.println(s);
            }
    
            Set<Integer> set = new HashSet<Integer>();
            set.add(10);
            set.add(20);
            set.add(30);
            set.add(33);
            set.add(35);
    
            //需求3:得到年龄大于25的流
            Stream<Integer> integerStream = set.stream().filter(age -> age > 25);
    
            //需求4:把使用Stream流操作完毕的数据收集到Set集合中并遍历
            Set<Integer> collect2 = integerStream.collect(Collectors.toSet());
            for (Integer i : collect2) {
                System.out.println(i);
            }
    
            String[] strArray = {"张飞,28", "张三丰,33", "张三,26", "李四,44"};
    
            //需求5:得到字符串年龄中数据大于28的流
            Stream<String> stringStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 28);
    
            //需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串的姓名作为键,年龄作为值
            Map<String, Integer> map = stringStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));
            Set<String> keySet = map.keySet();
            for (String key : keySet) {
                Integer value = map.get(key);
                System.out.println(key + "," + value);
            }
        }
    }

    以上がJava関数型プログラミングのサンプル分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明
    この記事は亿速云で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
    高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか?高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか?Mar 17, 2025 pm 05:46 PM

    この記事では、Javaプロジェクト管理、自動化の構築、依存関係の解像度にMavenとGradleを使用して、アプローチと最適化戦略を比較して説明します。

    適切なバージョン化と依存関係管理を備えたカスタムJavaライブラリ(JARファイル)を作成および使用するにはどうすればよいですか?適切なバージョン化と依存関係管理を備えたカスタムJavaライブラリ(JARファイル)を作成および使用するにはどうすればよいですか?Mar 17, 2025 pm 05:45 PM

    この記事では、MavenやGradleなどのツールを使用して、適切なバージョン化と依存関係管理を使用して、カスタムJavaライブラリ(JARファイル)の作成と使用について説明します。

    カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか?カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか?Mar 17, 2025 pm 05:44 PM

    この記事では、カフェインとグアバキャッシュを使用してJavaでマルチレベルキャッシュを実装してアプリケーションのパフォーマンスを向上させています。セットアップ、統合、パフォーマンスの利点をカバーし、構成と立ち退きポリシー管理Best Pra

    キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPA(Java Persistence API)を使用するにはどうすればよいですか?キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPA(Java Persistence API)を使用するにはどうすればよいですか?Mar 17, 2025 pm 05:43 PM

    この記事では、キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPAを使用することについて説明します。潜在的な落とし穴を強調しながら、パフォーマンスを最適化するためのセットアップ、エンティティマッピング、およびベストプラクティスをカバーしています。[159文字]

    Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか?Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか?Mar 17, 2025 pm 05:35 PM

    Javaのクラスロードには、ブートストラップ、拡張機能、およびアプリケーションクラスローダーを備えた階層システムを使用して、クラスの読み込み、リンク、および初期化が含まれます。親の委任モデルは、コアクラスが最初にロードされ、カスタムクラスのLOAに影響を与えることを保証します

    See all articles

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    AI Hentai Generator

    AI Hentai Generator

    AIヘンタイを無料で生成します。

    ホットツール

    SublimeText3 Mac版

    SublimeText3 Mac版

    神レベルのコード編集ソフト(SublimeText3)

    DVWA

    DVWA

    Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

    SublimeText3 中国語版

    SublimeText3 中国語版

    中国語版、とても使いやすい

    mPDF

    mPDF

    mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

    EditPlus 中国語クラック版

    EditPlus 中国語クラック版

    サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません