Java:函数式编程

1.Lambda基础

Lambda表达式的作用就是:减少代码的冗余量,相对于内部匿名类可读性增强

1.1普通函数定义:

// 返回类型 方法名 参数列表 方法体
int add (int a, int b) { return a+b; }

1.2省略过程

  • step1:返回类型和方法名直接省略,使用lambda操作符 -> 连接
(int a, int b) -> { return a+b; }
  • step2:参数类型省略,并且要省略全都得省略
(a, b) -> { return a+b; }
  • step3:如果参数只有一个,则省略小括号,以新函数为例:
int pow(int x) { return x*x; }
x -> { return x*x; }
  • step4:如果方法体中只有一句代码,则省略大括号和分号
(a, b) -> return a+b;
  • step5:如果仅剩的一句代码是返回语句,则return必须跟随大括号一起省略
(a, b) -> a+b
  • step6:如果无参数,则保留一对小括号,以新函数为例:
int get100() { return 100; }
() -> 100

2.函数式接口

有且只有一个抽象方法,但是可以有多个非抽象方法的接口,就是函数式接口。

2.1Lambda表达式和函数式接口的关系

Lambda表达式就是专门给函数式接口的形参或变量赋值用的。

2.1.1举例:调用自定义函数式接口

package test;

public class lambda {

    @FunctionalInterface // 该注解作用:标明为函数式接口,编译阶段会检查其内部是否有且只有一个抽象方法
    public  interface MyFunctionalInterface{ // 自定义函数式接口
        void method(); //抽象方法
    }

    // 定义一个“参数为函数式接口”的方法
    public static void doSomething(MyFunctionalInterface functionalInterface) {
        functionalInterface.method();//调用函数式接口里的方法
    }

    // 定义一个“返回值为函数式接口”的方法,普通方法实现
    public static MyFunctionalInterface getSomething(){
        return new MyFunctionalInterface() {
            @Override
            public void method() {
                System.out.println("返回值为一个匿名之类,普通方法实现");
            }
        };
    }

    // 定义一个“返回值为函数式接口”的方法,Lambda表达式方式实现
    public static MyFunctionalInterface getSomethingLambda(){
        return () -> System.out.println("返回值为一个匿名之类,Lambda表达式方式实现");
    }

    public static void main(String[] args){
        // 因为是static的方法,所以可以直接调用
        // 普通方式调用函数式接口并重写抽象方法
        doSomething(new MyFunctionalInterface() {
            @Override
            public void method() {
                System.out.println("111");
            }
        });

        // Lambda表达式方式调用函数式接口并重写抽象方法
        doSomething(()->System.out.println("222"));

        MyFunctionalInterface m1 = getSomething();
        m1.method();

        MyFunctionalInterface m2 = getSomethingLambda();
        m2.method();
    }
}

额外的小问题:抽象类不是不能实例化吗?为什么上面“普通方式调用”的代码实例化抽象类了?

答:上面的代码中并不是实例化抽象类,而是创建了一个匿名子类,实例化的是匿名子类,并不是抽象类。

2.1.2举例:调用系统提供的函数式接口

package test;

public class lambda {

    public static void doRunnable(Runnable runnable){
        runnable.run();
    }

    public static void testRunnable(){
        System.out.println("开始调用");
        doRunnable(()->System.out.println("调用第1个Runnable"));
        doRunnable(()->System.out.println("调用第2个Runnable"));
        System.out.println("结束调用");
    }

    public static void testThread() {
        System.out.println("开始调用线程");
        new Thread(()-> System.out.println("调用第1个线程")).run();
        new Thread(()-> System.out.println("调用第2个线程")).run();
        System.out.println("结束调用线程");
    }

    public static void main(String[] args) throws InterruptedException {
        testRunnable();
        System.out.println("--------------------");
        testThread();
    }
}

2.1.3总结

Lambda表达式的使用场景就是“创建函数式接口的(匿名)子类,并将(匿名)子类作为参数或返回值传递时,可以使用Lambda表达式简写其重写的方法”

这句话完全可以换成“继承并实例化函数式接口,然后将实例化的对象作为参数或返回值传递时,可以使用Lambda表达式简写其重写的方法”,但是这不如上面那句好,因为上面描述的场景比下面这句描述的场景更具体。

2.3Java内置的四大函数式接口

函数式接口 特点 举例
消费型Consumer 有参数无返回值
供给型Supplier 无参数有返回值
判断型Predicate 返回值为布尔类型
功能型Function<T,R> 有参数有返回值

3.方法引用

如果某个方法的签名和某个函数式接口中的抽象方法恰好一致,那么可以直接使用该方法的引用。

package test;

public class lambda {

    @FunctionalInterface // 该注解作用:标明为函数式接口,编译阶段会检查其内部是否有且只有一个抽象方法
    public  interface MyFunctionalInterface{ // 自定义函数式接口
        double method(double a,double b); //抽象方法
    }

    // 定义一个“参数为函数式接口”的方法
    public static double doSomething(MyFunctionalInterface functionalInterface) {
        return functionalInterface.method(3,2);//调用函数式接口里的方法
    }

    // 自定义定义一个"方法签名和函数式接口相同"的方法
    public static double add(double x,double y){
        return x + y;
    }

    // Math类中的pow方法的方法签名就是 double (num1,num2),恰好和MyFunctionalInterface中的method一致
    public static void main(String[] args){
        double d1 = doSomething(lambda::add);   // 调用自定义函数式接口,使用自定义add方法的引用
        double d2 = doSomething(Math::pow);     // 调用自定义函数式接口,使用Math类中pow方法的引用
        System.out.println(d1);
        System.out.println(d2);
    }
}

猜你喜欢

转载自blog.csdn.net/w_y_x_y/article/details/106258116