Java中的lambda表达式

2022/4/14 9:13:14

本文主要是介绍Java中的lambda表达式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

lambda表达式:

new Thread(()-> System.out.println("Hello World!")).start();

为什么要使用lambda表达式?

  • 避免匿名内部类定义过多
  • 可以让代码看起来简洁
  • 去掉了一堆没有意义的代码,只留下核心的逻辑

Functional Interface(函数式接口)

  • 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
public interface Runnable {
    public abstract  void run();
}
  • 对于函数式接口,可以通过lambda表达式来创建该接口的对象

函数式接口的推导

首先定义一个函数式接口

interface MyInterface {
    abstract void MyFunction(String str);
}

若要实现这个接口,正常情况下我们需要写一个接口实现类,然后通过new这个类的对象来调用其中的方法:

//实现函数式接口
class MyClass implements MyInterface {
    @Override
    public void MyFunction(String str) {
        System.out.println(str);
    }
}

public class TestLambda {
    public static void main(String[] args) {
        //通过接口new一个MyClass对象,然后调用方法
        MyInterface myInterface = new MyClass();
        myInterface.MyFunction("接口实现类方法");
    }
}

为了调用接口中的方法,需要单独定义一个接口的实现类,不是很方便,于是在我们在同一个类中定义静态内部类:

public class TestLambda {
    //定义静态内部内
    static class MyClass2 implements MyInterface {
        @Override
        public void MyFunction(String str) {
            System.out.println(str);
        }
    }
    public static void main(String[] args) {
        //创建MyClass2对象调用方法
        MyInterface myInterface = new MyClass2();
        myInterface.MyFunction("静态内部类方法");
    }
}

可以看到,MyClass2定义在方法外面,依然有些繁琐,于是我们开始使用局部内部类:

public class TestLambda {
    public static void main(String[] args) {
        //定义在函数内的局部内部类
        class MyClass3 implements MyInterface {
            @Override
            public void MyFunction(String str) {
                System.out.println(str);
            }
        }
        //创建MyClass3对象调用方法
        MyInterface myInterface = new MyClass3();
        myInterface.MyFunction("局部内部类方法");
    }
}

为了进一步简化,我们还可以使用匿名内部类:

public class TestLambda {
    public static void main(String[] args) {
        //创建匿名内部类调用方法
        new MyInterface() {
            @Override
            public void MyFunction(String str) {
                System.out.println(str);
            }
        }.MyFunction("匿名内部类方法");
    }
}

演化到这里,代码已经很精简了,但是依然有繁琐的代码导致核心代码依然不突出,为了进一步简化,只突出核心代码,我们使用了lambda来简化:

接口 = (参数列表) -> {

        代码;

};

其中,参数列表依据函数式接口中的方法参数而定,可以没有,也可以有多个

lambda表达式使代码达到了最简,只保留了接口名,参数和执行体

public class TestLambda {
    public static void main(String[] args) {
        MyInterface myInterface = (String str) -> System.out.println(str);
        myInterface.MyFunction("lambda表达式方法");
    }
}

到此,我们清楚了lambda表达式的由来,最终的效果是我们定义一个函数式接口,通过一句lambda表达式就能调用里面的方法。lambda表达式使代码达到了最精简,只突出核心语句,去掉了没有意义的代码。

public class TestLambda {
    public static void main(String[] args) {
        MyInterface myInterface = (String str) -> System.out.println(str);
        myInterface.MyFunction("lambda表达式方法");
    }
}

//定义一个函数式接口
interface MyInterface {
    abstract void MyFunction(String str);
}

不知大家是否发现,文章最开头给出的代码是带new关键字的,我们用自己写的函数式接口不能用lambda函数作为参数把对象new出来,不知大家是否陷入了疑惑。别忘了,接口是不能被实例化的!如果一个接口能被实例化,只能说明他不是一个接口,而是一个类!

事实上,文章开头给出的lambda表达式

new Thread(()-> System.out.println("Hello World!")).start();

是一个匿名内部类,Thread并不是函数式接口,而是函数式接口Runnable的实现类,因为接口是不能被实例化的,若Thread是函数式接口则不能使用new关键字创建对象。根据上述推理lambda的过程向上倒推,我们会发现实际上上述语句等价于:

new Thread() {
            @Override
            public void run() {
                System.out.println("Hello World!");
            }
        }.start();

通过查看Java源码可以看到,Thread类中存在接收一个参数的构造方法,而start()方法调用了start0()方法,start0()又调用了run()方法,因此上述代码又相当于:

new Thread() {
            @Override
            public void run() {
                System.out.println("Hello World!");
            }
        }.run();

实际测试运行结果也确实相同,到这里我们不难看出,这就是一个实现了一个接口并重写接口中方法的匿名内部类。

那么新问题又来了,为什么说lambda表达式只支持函数式接口,是不是意味着函数式接口和实现了函数式接口的类都能用lambda表达式?事实上,lambda表达式作为参数值时,只需要形参类型为函数式接口即可,与类是否实现函数式接口无关。

public class Test02 {

    public static void main(String[] args) {
        //构造匿名内部类,lambda表达式作为参数
        new TestClass(() -> System.out.println("AAAA")) {
            @Override
            void tests() {
                System.out.println("BBBB");
            }
        }.tests();
    }
}

//TestClass类并没有实现Runnable接口
class TestClass {
    //构造方法,接收参数类型为函数式接口Runnable
    public TestClass(Runnable runnable) {
    }

    void tests() {
        System.out.println("CCCC");
    }
}

当然,该段代码纯属为了搞清楚语法规则,并没有实际意义。因此,lambda表达式只支持函数式接口(只有一个抽象方法的接口)是因为lambda表达式作为参数时,只能用函数式接口作为形参来接收。

本人仅仅是因为对Java中的lambda感兴趣进行研究后的记录,把结果记录并分享出来,如果对大家有任何帮助我感到万分荣幸,因个人水平有限,文章中可能存在错误或者不正确的观点,欢迎大家批评指出。



这篇关于Java中的lambda表达式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程