10.Java学习笔记----Lambda表达式

第十章:Lambda表达式

第一节:函数式编程思想概述

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

**面向对象的思想:**做一件事情,找一个能解决这个事情的对象,调用对象的方法完成事情

**函数式编程思想:**只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程

第二节:冗余的Runnable代码

原始代码:

RunnableImpl run=new RunnableImpl();
Thread th=new Thread(run);
th.start();

匿名内部类用法:

new Thread(new Runnable() {
@Override
public void run() {
	System.out.println(Thread.currentThread().getName()+"又创建了");
	}
}).start();

代码分析:

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

  • Thread类需要Runnable接口作为参数,其中的抽象run方法是用来指定线程任务内容的核心
  • 为了指定run的方法体,不得不需要Runnable接口的实现类
  • 为了省去定义一个RunnableImpl实现类的麻烦,不得不使用匿名内部类
  • 必须覆盖重写抽象run方法,所以方法名称、方法参数、方法返回值不得不重写一遍,且不能写错
  • 而实际上,似乎只有方法体才是关键所在

第三节:编程思想转换

做什么。而不是怎么做

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

传递一段代码——这才是我们真正的目的。而创建对象只是受限于面向对象语法而不得不采取的一种手段方式。如果我们将关注点从“怎么做“回归到”做什么“的本质上,就会发现只要能够更好地达到目的,过程与形式其实并不重要

在2014年3月Oracle发布的Java8(JDK1.8)中,加入了Lambda表达式的重量级新特性

Lambda表达式创建多线程与匿名内部类创建多线程对比:

public class Lambda_Creat {
    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();
    }
}
语义分析:

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

  • public abstract void run();

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

  • **无参数:**不需要任何条件即可执行该方案
  • **无返回值:**该方案不产生任何结果
  • **代码块(方法体):**该方案的具体执行步骤

同样的语义体现在Lanbda语法中,要更加简单:

()->{System.out.println("多线程任务执行");}
  • 前面的一对小括号即run方法的参数(无),代表不需要任何条件
  • 中间的一个箭头代表将前面的参数传递给后面代码
  • 后面的输出语句即业务逻辑代码

第四节:Lambda标准格式

Lambda格式由三部分组成:

  • 一些参数
  • 一个箭头
  • 一段代码

Lambda表达式的标准格式为:

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

解释说明格式:

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

->:传递的意思,把参数传递给方法体{}

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

第五节:练习:使用Lambda标准格式(无参数返回)

题目:

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

public interface Cook{
    void makeFood();
}

在下面的代码中,请使用Lambda的标准格式调用invokeCook方法,打印输出“吃饭了”字样:

public class Cook_Main {
    public static void main(String[] args) {
        //请再此使用Lambda【标准格式】调用invokeCook方法
        invokeCook(()->{
            System.out.println("吃饭了");
        });
    }

    private static void invokeCook(Cook cook){
        cook.makeFood();
    }
}

第六节:Lambda的参数和返回值

需求:

1、使用数组存储多个Person对象

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

public class Lambda_Main {
    public static void main(String[] args) {
        Person[] arr={
                new Person("柳岩",18),
                new Person("迪丽热巴",19),
                new Person("古力娜扎",15)
        };
        //使用匿名内部类实现重写方法
        Arrays.sort(arr, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge()-o2.getAge();
            }
        });
        
        //使用Lambda表达式实现重写方法
        Arrays.sort(arr,(Person o1,Person o2)->{
            return o1.getAge()-o2.getAge();
        });
        for (Person person:arr) {
            System.out.println(person);
        }
    }
}

第七节:练习:使用Lambda标准格式(有参有返回)

题目:

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

public interface Calculator{
    int calc(int a,int b);
}
public class Main {
    public static void main(String[] args) {
        //请在此使用Lambda表达式【标准格式】调用invokeCalc方法计算120+130的结果
        //使用匿名内部类
        invokeCalc(120, 130, new Calculator() {
            @Override
            public int calc(int a, int b) {
                return a+b;
            }
        });
        //使用Lambda表达式
        invokeCalc(120,130,(int a,int b)->{
            return a+b;
        });

    }

    private static void invokeCalc(int a,int b,Calculator calculator){
        int result=calculator.calc(a,b);
        System.out.println("结果是:"+result);
    }
}

第八节:Lambda省略格式

Lambda表达式:是可推导、可省略的

范式根据上下文推导出来的内容,都可以省略

可以省略的内容:

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

2、(参数列表):括号中的参数如果只有一个,那么类型和()都可以省略

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

  • 注意:要省略{},return,;必须一起省略

第九节:Lambda使用前提

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

  • 无论是JDK内置的RunnableComparator接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda

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

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

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

你可能感兴趣的:(笔记,个人笔记,java)