• Java8 巨强大的新特性 lambda表达式


    目录

    一、定义

    二、lambda表达式的语法

     三、常见的lambda表达式使用场景

    四、再提经典使用 

    五、匿名内部类与lambda表达式区别


    为什么引入lambda表达式?

    到目前为止(java7之前),在Java中传递一个代码段并不方便,你不能直接传递代码段。因为Java是一种面向对象的语言,所以必须创建一个对象,由这个对象实现所需方法片段》。

    设计者们做了多年尝试,终于找到了一种适合Java的设计——lambda表达式

    一、定义

    《Java核心技术 I》里是这么定义的:

    lambda表达式是一个可传递的代码块,可以在以后一次或多次执行,它采用了一种简洁的方式来定义代码块。

    1、传统方式调用

    1. //接口实现
    2. public class Runnable1 implements Runnable {
    3. @Override
    4. public void run() {
    5. System.out.println("执行了多线程方法!");
    6. }
    7. }
    8. public class MyLambda1 {
    9. public static void main(String[] args) {
    10. Runnable1 lambda1=new Runnable1();
    11. Thread thread=new Thread(lambda1);
    12. thread.run();
    13. }
    14. }

    2、匿名内部类

    1. public class MyLambda1 {
    2. public static void main(String[] args) {
    3. Runnable lambda2 = new Runnable() {
    4. @Override
    5. public void run() {
    6. System.out.println("执行了多线程方法!");
    7. }
    8. };
    9. Thread thread=new Thread(lambda2);
    10. thread.run();
    11. }
    12. }

    3、lambda表达式

    1. public class MyLambda1 {
    2. public static void main(String[] args) {
    3. //3、lambda表达式
    4. Thread thread=new Thread(()->{
    5. System.out.println("执行了多线程方法!");
    6. });
    7. thread.run();
    8. }
    9. }

    可能会有同学要问了,匿名内部类跟lambda表达式感觉没多大区别啊!能不能不学啊!

    lambda表达式确实写法简洁了,而且实现方式是不同(后面会比较二者的不同)。

    二、lambda表达式的语法

    Lambda表达式的语法格式:

    (参数列表  ) - > { 语句或语句块 }

    • ( ):若为空,则接口方法没有参数
    • - >:箭头指向{}中的方法代码块
    • { }:包含一段代码块,即方法体中的内容

    【例子展示】

    1、无参数无返回值

    1. public interface Cat {
    2. void say();
    3. }
    4. public class Lambda2 {
    5. public static void main(String[] args) {
    6. testCat(() -> {
    7. System.out.println("猫叫声:喵!喵!喵!");
    8. });
    9. }
    10. public static void testCat(Cat cat) {
    11. cat.say();
    12. }
    13. }

    2、带参数无返回值

    1. public interface Dog {
    2. void call(String msg);
    3. }
    4. public class Lambda2 {
    5. public static void main(String[] args) {
    6. testDog((String msg) -> {
    7. System.out.println("狗叫声:" + msg);
    8. });
    9. }
    10. public static void testDog(Dog dog) {
    11. dog.call("汪!汪!汪!");
    12. }
    13. }

    3、带参数有返回值

    1. public interface Operation {
    2. int add(int n, int m);
    3. }
    4. public class Lambda2 {
    5. public static void main(String[] args) {
    6. testOperation((int n,int m) -> {
    7. return n+m;
    8. });
    9. }
    10. public static void testOperation(Operation operation) {
    11. System.out.println(operation.add(10, 20));
    12. }
    13. }

    【 写法简化】:

    • 单个参数可省略()
    • 参数类型可以省略(必须同时省略或者不省略)
    • 方法体单语句可以省略 {  }
    1. /省略参数括号、方法体括号
    2. testDog(msg -> System.out.println("狗叫声:" + msg));
    3. //方法引用
    4. //打印对象是传入参数
    5. testDog(System.out::println);

     三、常见的lambda表达式使用场景

    在《JAVA核心技术 I》中这样描述:

            使用 lambda表达式的重点是延迟执行(deferred execution)毕竟,如果想要立即执行代
    码,完全可以直接执行,而无须把它包装在一个 lambda表达式中。之所以希望以后再执行
    代码,这有很多原因,如:

    • 在一个单独的线程中运行代码;
    • 多次运行代码;
    • 在算法的适当位置运行代码(例如,排序中的比较操作);
    • 发生某种情况时执行代码(如,点击了一个按钮,数据到达,等等);
    • 只在必要时才运行代码;

    1、重复执行代码:

    1. repeat(10, () -> System.out.println("Hello,World!"));
    2. public static void repeat(int n, Runnable action) {
    3. for (int i = 0; i < n; i++) {
    4. action.run();
    5. }
    6. }

     2、延迟执行(必要时才运行、发生某种情况时执行代码)

    javaFX中给按钮绑定事件,某一事件才触发按钮

    1. Button button = new Button("按钮");
    2. button.setOnAction(event -> {
    3. //do something
    4. });

    3、在算法的适当位置运行代码(例如,排序中的比较操作)

    在compartor的比较方法执行结束前,不会进行排序。

    1. //自定义数组
    2. String [] arg={"acc","ddd","aaa","bbb","ccc"};
    3. Arrays.sort(arg,(first,second)->{
    4. return first.length()-second.length();
    5. });

    四、再提经典使用 

    1、Java的四大函数式接口

     a、Consumer

    表示接受单个输入参数且不返回结果的操作。 与大多数其他功能界面不同,Consumer被期望通过副作用来操作。 

    1. public class ConsumerTest1 {
    2. public static void main(String[] args) {
    3. String [] arr={"花木兰,21","小乔,23","孙尚香,22"};
    4. consumer(arr, (s)->{
    5. System.out.print(s.split(",")[0]);
    6. }, new Consumer<String>() {
    7. @Override
    8. public void accept(String s) {
    9. System.out.println(","+Integer.parseInt(s.split(",")[1]));
    10. }
    11. });
    12. }
    13. //消费方法
    14. public static void consumer(String[] arr, Consumer<String> con1, Consumer<String> con2) {
    15. for (String str : arr) {
    16. con1.andThen(con2).accept(str);
    17. }
    18. }
    19. }

    b、Supplier

    • 表示结果的提供者。  
    • 并不要求每次调用供应商时都返回一个新的或不同的结果。  
    • 这是一个函数式接口,其函数方法是get()。 

    1. public class SupplierTest {
    2. public static void main(String[] args) {
    3. String s1 = getString(() -> {
    4. return "彭于晏";
    5. });
    6. System.out.println("lambda表达式:"+s);
    7. }
    8. //消费方法
    9. public static String getString(Supplier<String> sup){
    10. return sup.get();
    11. }
    12. }

    c、Predicate

    • 表示一个参数的谓词(布尔值函数)。  
    • 这是一个功能接口,其功能方法是test(Object)。

    1. public class PredicateTest {
    2. public static void main(String[] args) {
    3. String[] arg = {"aaaa", "bb", "cccc"};
    4. List<String> stringList = filter(arg
    5. , (obj) -> obj.toString().startsWith("a")
    6. , (obj) -> obj.toString().length() > 3);
    7. System.out.println(stringList.get(0));
    8. }
    9. public static List<String> filter(String[] arg, Predicate p1, Predicate p2) {
    10. List<String> result = new ArrayList<>();
    11. for (String s : arg) {
    12. if (p1.and(p2).test(s)) {
    13. result.add(s);
    14. }
    15. }
    16. return result;
    17. }
    18. }

    d、Function

    2、steam流的使用

    需求:字符数组中去掉以首字为d开头,再得到所有长度大于3的字符串,再按字典序排序输出。

    1. //自定义数组
    2. String [] arg={"acc","ddd","aaa","bbb","ccc"};
    3. Arrays.stream(arg)
    4. .filter((obj)->obj.toString().startsWith("a"))
    5. .filter((obj)->obj.toString().length()>3)
    6. .forEach(System.out::println);

    五、匿名内部类与lambda表达式区别

    1、所需类型不同;

    匿名内部类:接口,抽象类,也可具体类;

    Lambda表达式: 接口;

    2、使用限制

    接口只有一个抽象方法,两者都可以使用;多个抽象方法,只能使用匿名内部类;

    3、实现原理

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

    lambda表达式:编译之后,没有单独的.class字节码文件,对应的字节码在运行时动态生成,不会保留到本地的硬盘之中;


    觉得文章好不错的话三连支持一下吧!

    别逼我求你……

  • 相关阅读:
    数据化运营18 营收:如何通过交叉营销提升用户营收贡献?
    【微信小程序】NFC 标签打开小程序
    2020年江西省职业院校技能大赛软件测试技能竞赛方案(高职组)
    linux 部署dns正向解析服务,照做就可以
    如何使用libswscale库将YUV420P格式的图像序列转换为RGB24格式输出?
    【Linux篇】第十一篇——动静态库(动静态库的介绍+动静态库的打包与使用)
    ssh指定的密钥协商方式以及Ansible的hosts文件修改密钥协商方式
    使用vite搭建前端项目
    LeetCode //C - 190. Reverse Bits
    【游戏编程扯淡精粹】工作两年总结
  • 原文地址:https://blog.csdn.net/m0_46013789/article/details/125389167