ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java中的lambda表达式

2022-04-14 02:00:58  阅读:174  来源: 互联网

标签:Java String void 接口 new public 表达式 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,String,void,接口,new,public,表达式,lambda
来源: https://www.cnblogs.com/chuyasupport/p/Java-lambda.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有