Java基础-------Lambda表达式详细说明

1.传统代码写法(线程举例)

1.使用实现类创建线程

  1. 要启动一个线程,需要创建一个Thread类的对象并调用start方法。而为了指定线程执行的内容,需要调用Thread类的构造方法:

    public Thread(Runnable target)
    
  2. 为了获取Runnable接口的实现对象,可以为该接口定义一个实现类RunnableImpl

    package Lambda;
    
    /**
     * @author JIN
     * @description
     * @createTime 2020-08-25 08:55
     **/
    public class RunnableImpl implements Runnable {
    
        @Override
        public void run() {
            System.out.println("启动线程了.....");
        }
    }
    
  3. 然后创建该实现类的对象作为Thread类的构造参数:

    package Lambda;
    
    /**
     * @author JIN
     * @description 使用实现类 创建线程
     * @createTime 2020-08-25 08:57
     **/
    public class Demo1 {
        public static void main(String[] args) {
            Runnable task = new RunnableImpl();
            new Thread(task).start();
        }
    }
    
    

2.使用实现类创建线程的问题

  1. 刚刚我们创建的RunableImpl类只是为了实现Runnable接口而存在的,而且仅仅是被使用唯一的一次,且若以后你创建的线程数量很多,且需要执行的方法不同,那么就要创建相同数量的实现类,造成整体代码的冗余。
  2. 因此,就诞生了使用匿名内部类来创建线程。

3.使用匿名内部类创建线程

  1. 通过刚刚的分析,我们知道RunableImpl实现类的只是为了实现Runnable接口而存在的,该方法则要重新创建一个类,实在太麻烦了,因此使用匿名内部类还可以省去类的单独定义。

  2. 代码如下:

    package Lambda;
    
    /**
     * @author JIN
     * @description 使用匿名内部类创建线程
     * @createTime 2020-08-25 09:05
     **/
    public class Demo2 {
        public static void main(String[] args) throws InterruptedException {
        	//第一种匿名内部类的使用
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程启动了1....");
                }
            };
            new Thread(task).start();
            
            Thread.sleep(1000);
            System.out.println("-----------------");
    		//我们还发现第一种方法中还可以简化,因此引出下面的方法
    		//更加简化
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程启动了2......");
                }
            }).start();
        }
    }
    
    

4.使用匿名内部类创建线程的好处与弊端

1.好处

  1. 匿名内部类当然可以帮我们省去实现类的定义。使我们实现代码起来更加简单快捷。

2.弊端

  1. 语法的复杂性。使用匿名内部类,必须覆盖重写抽象方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错。(但是实际上开发工具都有自动帮你写好的功能,其实这个弊端也不算什么).

  2. 还是不够简化,始终还是有冗余,代码如下:

    package Lambda;
    
    /**
     * @author JIN
     * @description 匿名内部类的冗余
     * @createTime 2020-08-25 09:18
     **/
    public class Demo3 {
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("A.........");
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("B.........");
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("C.........");
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("D.........");
                }
            }).start();
        }
    }
    
    
  3. 细心的人应该发现了,代码中存在大量重复的,比如下面:

    		 new Thread(new Runnable() { //new Runnable 重复
    	            @Override   //重复
    	            public void run() { //重复
    	                
    	            }
    	        }).start();
    

2.分析两种传统方法的实现

  1. 我们通过刚刚的上面的代码,可以分析出以下几点内容:
  2. Thread类需要Runnable接口作为参数,其中的抽象run方法是用来指定线程任务内容的核心。
  3. 为了指定run的方法体,不得不需要Runnable接口的实现类。
  4. 为了省去定义一个RunnableImpl实现类的麻烦,不得不使用匿名内部类。
  5. 必须覆盖重写抽象run方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错。
  6. 而实际上,似乎只有方法体才是关键所在,因为我们需要的使run方法内部中执行的内容。

3.使用Lamda表达式

1.函数式编程思想概述

  1. 面向对象的思想,过分强调“必须通过对象的形式来做事情”,即做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情。(比如:电脑坏了,但是自己又不会修,那就去找专业人士(专业人士即是对象),然后专业人士使用他的专业技能(即调用对象的方法)修好了电脑)
  2. 函数式编程思想,只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程。(比如你要去北京,可以走路,坐飞机,坐火车等等方式,但是你都无所谓,只要能到北京就好了)

2.编程思想转换

  1. 我们真的希望创建一个匿名内部类对象吗?不。我们只是为了做这件事情而不得不创建一个对象。我们真正希望做的事情是:将run方法体内的代码传递给Thread类知晓
  2. 传递一段代码——这才是我们真正的目的。而创建对象只是受限于面向对象语法而不得不采取的一种手段方式。
  3. 现在我们有更加快捷的方式-----Lambda表达式。

3. 使用Lambda创建线程

1.Lambda标准格式

  1. Lambda表达式的标准格式为 (参数类型 参数名称) -> { 代码语句 }
  2. 小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
  3. ->是新引入的语法格式,代表指向动作,将前面的参数传递给后面的代码。
  4. 大括号内的语法与传统方法体要求基本一致。

2.初步使用Lambda

  1. 代码如下:

    package Lambda;
    
    /**
     * @author JIN
     * @description 使用Lambda表达式
     * @createTime 2020-08-25 09:44
     **/
    public class Demo4 {
        public static void main(String[] args) {
            new Thread(() -> {
                System.out.println("线程启动了...");
            }).start();
        }
    }
    
    

3.Lambda省略格式

  1. Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。

  2. 在Lambda标准格式的基础上,使用省略写法的规则为:

  3. 小括号内参数的类型可以省略;

  4. 如果小括号内有且仅有一个参,则小括号可以省略;

  5. 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号且这三个必须同时省略。

  6. 代码如下:

    package Lambda;
    
    /**
     * @author JIN
     * @description 使用Lambda表达式省略模式
     * @createTime 2020-08-25 09:44
     **/
    public class Demo5 {
        public static void main(String[] args) {
            new Thread(() -> System.out.println("线程启动了...")).start();
        }
    }
    
    

4.Lambda练习

  1. 给定一个计算器Calculator接口,内含抽象方法calc可以将两个int数字相加得到和值:

  2. 代码如下:

    package Lambda;
    
    public interface Calculator {
        int add(int a,int b);
    }
    
    package Lambda;
    
    /**
     * @author JIN
     * @description 使用Lambda标准格式(有参有返回)
     * @createTime 2020-08-25 09:53
     **/
    public class Demo6 {
        public static void main(String[] args) {
            //标准模式
            invokeCalc(10,20,(int a, int b)->{
                return a + b;
            });
    
            //省略模式,可以看出更加省略
            invokeCalc(100,200,(a, b) -> a + b);
        }
    
        private static void invokeCalc(int a, int b, Calculator calculator){
            int result = calculator.add(a, b);
            System.out.println(result);
        }
    }
    
    
  3. 使用Lambda标准格式(只有一个参且有返回)

    package Lambda;
    
    public interface Calculator {
        int add(int a);
    }
    
    
    package Lambda;
    
    /**
     * @author JIN
     * @description 使用Lambda标准格式(有一个参有返回)
     * @createTime 2020-08-25 09:53
     **/
    public class Demo7 {
        public static void main(String[] args) {
            //只有一个参数则小括号可以省略
            //标准模式
            invokeCalc(10,a ->{
                return a;
            });
    
            //省略模式,可以看出更加省略
            invokeCalc(100,a ->a);
        }
    
        private static void invokeCalc(int a,Calculator calculator){
            int result = calculator.add(a);
            System.out.println(result);
        }
    }
    
    

5.总结

  1. Lambda的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:
  2. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。无论是JDK内置的RunnableComparator接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
  3. 使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
  4. 有且仅有一个抽象方法的接口,称为“函数式接口”。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值