Tips:样式蚂蚁森林浇水get

Lambda表达式

Lambda表达式

函数式编写思想概述

   在数学中,函数就是输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思维则是尽量忽略面向对象的复杂语法--强调做什么么,而不是怎么做。

   面向对象的思维:

  做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成任务。

  函数式编程思想:

  只要能获得结果,谁去做,怎么做的都不在乎,重视的是结果而不是过程

冗余的Runnable代码

  1、传统写法  

package day07.day07_2;
//Runnbale实现类
public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+" 新线程被创建了");
    }
}
Runnable实现类

 

package day07.day07_2;
//了解Runnable的代码冗余现象
public class demo {
    public static void main(String[] args) {
        //第一种方式
        //创建实现类对象
        RunnableImpl run = new RunnableImpl();
        //创建Thread 传递run
        Thread t=new Thread(run);
        //开启线程
        t.start();//Thread-0 新线程被创建了

        //方式二--简化 创建匿名内部类(无需单独创建实现类)
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+" 新线程被创建了");
            }
        };
        new Thread(r).start();

        //最简形式
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName()+" 新线程被创建了");
                    }
                }
        ).start();
    }
}
逐步简化Runnable

  2、代码分析

  对于Runnable的匿名内部类用法,可以分析出:

  Thread类需要Runnable接口作为参数,其中的run方法是用来指定线程任务内容的核心

  1.为了指定run的方法体,不得不需要Runnable接口的实现类。

  2.为了省去RunnableImpl实现类的麻烦,不得不使用匿名内部类。

  3.必须覆盖重写run方法,所以方法名、方法参数、方法返回值不得不重写,且不能写错。

  4.而实际上,似乎只有方法体才是关键所在

编程思想转换

  1、做什么,而不是怎么做

  我们真的希望创建一个匿名内部类对象吗?我们只是为了做这件事不得不创建一个对象。我们真正希望做的事情是:将run方法体内的代码传递给Thread知晓。

  传递一段代码--->这才是我们真正的目的

  2、生活举例

  

  当我们需要从广州到北京时,可以选择高铁、汽车、徒步或者骑行。我们的真正目的是到达北京,而如何才能到达北京的形式并不重要,所以我们一直探索有没有比高铁更好的方式---搭乘飞机

 

 

   而这种飞机已经诞生:2014年Oracle发布的Java8(JDK1.8)中,加入了lambda表达式的重量级新特性

体验Lambda的更优写法

  借助Java8的全新语法,上述Runnable接口的匿名内部类写法可以通过最简单Lambda表达式达到同样效果

  例如:

public class damo_Lambda {
    public static void main(String[] args) {
        //匿名内不类写法
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName()+" 新线程被创建了");
                    }
                }
        ).start();
        //Lambda表达式写法
        new Thread(
                ()->{
                    System.out.println(Thread.currentThread().getName()+"新的线程被创建了");
                }
        ).start();
        /**
         * Thread-0 新线程被创建了
         * Thread-1新的线程被创建了
         */
    }
}

 

  不再有"不得不创建接口对象"的束缚,不再有“抽象方法覆盖重写”的负担

匿名内部类的好处与弊端

  一方面,匿名内部类可以帮我们省去实现类;另一方面,匿名内部类的语法---过于复杂

  1、内部类语义分析

  仔细分析该代码的语义,Runnable接口只有一个run方法的定义:

  public abstract void run();

  即制定了一种做事方案(其实就是一个函数):

  无参:不需要任何条件就可以执行

  无返回值:该方案不产生结果

  代码块(方法体):该方案的具体执行步骤。

  2、同样语义,在Lambd语法中

  () -> {System.out.println("多线程执行")}

  前面的一对小括号(),即run方法的参数(无),表示无需任何条件

  中间的箭头->,代表将前面的参数传递给后面的代码

  后面的{}中的语句,即业务逻辑代码

Lambda表达式格式

  1、Lambda标准表达式:

  由三部分组成:

    a.一些参数

    b.一个箭头

    c.一段代码

  2、格式:

  (参数列表) -> {一些重写方法}

  3、解析:

  ():接口中抽象方法的参数列表,没有参数就空着;有参数就写出参数,多个参数逗号隔开

  ->:传递的意思,把方法传递给方法体

  {}:重写接口的抽象方法的方法体

练习:使用Lambda标准格式(无参)

  需求:给定一个厨子 Cook 接口,内含唯一的抽象方法 makeFood ,且无参数、无返回值 。

package day07.day07_3;
//创建Cook接口
public interface Cook {
    //定义makeFood抽象方法
    public abstract void makeFood();
}
Cook接口
package day07.day07_3;

public class demo {
    public static void main(String[] args) {
        method(
                new Cook() {
                    //重写接口中的抽象方法
                    @Override
                    public void makeFood() {
                        System.out.println("吃饭啦!!!");
                    }
                }
        );
        //使用Lambda表达式
        method(
                ()->{
                    System.out.println("Lambda吃饭啦");
                }
        );
    }
    //定义静态方法 传递Cook对象
    public static void method(Cook cook){
        //调用Cook中的方法
        cook.makeFood();
    }
}
内部类 V/S Lambda

Lambda的参数和返回值

  需求:

  使用数组存储多个Person对象

  对数组中的Person对象使用Arrays.sort方法,通过年龄进行升序排序

package day07.day07_4;
//创建Person类
public class Person {
    //成员变量
    private String name;
    private int age;

    //构造方法
    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //get & set
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    //重写toString
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Person类
package day07.day07_4;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

public class dome {
    public static void main(String[] args) {
        //创建数组 存储Person对象
       Person[] arr = {
               new Person("花千骨",18),
               new Person("白子画",40),
               new Person("杀阡陌",20)
       };
       //1.使用Arrays.sort方法 按照年龄升序
//        Arrays.sort(arr, new Comparator<Person>() {
//            @Override
//            public int compare(Person o1, Person o2) {
//                return o1.getAge()-o2.getAge();
//            }
//        });

        //2.使用Lambda表达式
        Arrays.sort(arr,(Person o1, Person o2)->{
            return o1.getAge()-o2.getAge();
        });

        //利用for循环打印
        for (Person p:arr
             ) {
            System.out.println(p.getName()+"--->"+p.getAge());
        }
        /**
         * 花千骨--->18
         * 杀阡陌--->20
         * 白子画--->40
         */
    }
}
内部类 V/S Lambda(带参)

练习:使用Lambda标准格式(含参与返回值)

 需求:

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

package day07.day07_5;
//定义计算器接口
public interface Calculator {
    //定义求和抽象方法
    public abstract int calc(int a,int b);
}
Calculator接口
package day07.day07_5;

public class demo {
    public static void main(String[] args) {
        //内部类写法
        invokeCalc(10, 20, new Calculator() {
            @Override
            public int calc(int a, int b) {
                return a+b;
            }
        });
        //Lambda写法
        invokeCalc(5,8,(int a,int b)->{
            return a+b;
        });
    }
    private static void invokeCalc(int a ,int b,Calculator cal){
        int result = cal.calc(a,b);
        System.out.println("计算结果为:"+result);
    }
}
内部类 V/S Lambda(带参带返回值)

 

Lambda省略格式

  Lambda强调(做什么而不是怎么做),所有凡是可以根据上下文推导得知的信息,都可以省略

  省略规则

  1.(参数列表):括号中参数列表的数据类型可以省略不写

package day07.day07_5;
//定义计算器接口
public interface Calculator {
    //定义求和抽象方法
    public abstract int calc(int a,int b);
}
Calculator接口
package day07.day07_5;

public class demo {
    public static void main(String[] args) {
        //内部类写法
        invokeCalc(10, 20, new Calculator() {
            @Override
            public int calc(int a, int b) {
                return a+b;
            }
        });
        //Lambda写法
        invokeCalc(5,8,(int a,int b)->{
            return a+b;
        });
        //Lambda省略写法
        invokeCalc(5,8,(a,b)->{
            return a+b;
        });
    }
    private static void invokeCalc(int a ,int b,Calculator cal){
        int result = cal.calc(a,b);
        System.out.println("计算结果为:"+result);
    }
}
Lambda省略写法

 

  2.(参数列表):括号中参数只有一个,类型和括号都可以不写

  3.{一些代码}:如果{}中的代码只有一行,无论是否有返回值都可以省略{}return

package day07.day07_5;
//定义计算器接口
public interface Calculator {
    //定义求和抽象方法
    public abstract int calc(int a,int b);
}
Calculator
package day07.day07_5;

public class demo {
    public static void main(String[] args) {
        //内部类写法
        invokeCalc(10, 20, new Calculator() {
            @Override
            public int calc(int a, int b) {
                return a+b;
            }
        });
        //Lambda写法
        invokeCalc(5,8,(int a,int b)->{
            return a+b;
        });
        //Lambda省略写法
        invokeCalc(5,8,(int a,int b)->a+b);
    }
    private static void invokeCalc(int a ,int b,Calculator cal){
        int result = cal.calc(a,b);
        System.out.println("计算结果为:"+result);
    }
}
Lambda省略写法

 

练习:Lambda省略格式

  需求:

  使用省略写法完成Cook练习

package day07.day07_6;

public interface Cook {
    public abstract void makeFood();
}
Cook接口
package day07.day07_6;

public class demo {
    public static void main(String[] args) {
        //使用Lambda省略格式
        method(()-> System.out.println("Lambda吃的真少呢"));
    }
    //创建静态方法 传递Cook对象
    public static void method(Cook cook){
        //调用cook的makefood方法
        cook.makeFood();
    }
}
Lambda省略格式

 

Lambda的使用前提

  Lambda的语法非常简洁,完全没有面向对象的复杂束缚,但是需要注意

  1、使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法

  无论是Runnable、还是Comparator接口、还是自定义接口,只有当接口中的抽象方法存在,才能使用Lambda

  2、使用Lambda必须具有上下文推断

  也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为接口

  3、有且仅有一个抽象方法的接口,称为“函数式接口”

  

 

posted @ 2021-03-27 21:57  心岛未晴  阅读(105)  评论(0)    收藏  举报