一、匿名内部类的好处与弊端

一方面,匿名内部类可以帮我们省去实现类的定义;
另一方面,匿名内部类的语法——确实太复杂了!

1.语义分析:

仔细分析该代码中的语义,Runnable接口只有一个run方法的定义:
    public abstract void run();
即制定了一种做事情的方案(其实就是一个函数):
    1.无参数:不需要任何条件即可执行该方案
    2.无返回值:该方案不产生任何结果
    3.代码块(方法体):该方案的具体执行步骤

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

() -> System.out.println("多线程任务执行")
    1.()就是参数列表,就是run方法的参数(无),代表不需要任何条件
    2. -> 就表示将前面的参数传递给后面的方法体
    3.后面的输出语句即业务逻辑代码

二、Lambda表达式的标准格式

1.引言

在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。

相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。

面向对象的思想:
    做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情。
函数式编程思想:
    只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程。

2 .Lambda表达式由三部分组成:

1.一些参数
2.一个箭头
3.一段代码

格式:
    (参数列表) -> {一些重写方法的代码};
    
解释说明格式:
    ():接口中抽象方法的参数列表,没有参数,就空着;有参数就写出参数,多个参数使用逗号分隔
    ->:传递的意思,把参数传递给方法体{}
    {}:重写接口的抽象方法的方法体

3.Example:使用实现Runnable接口的方式实现多线程程序

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

进而可以使用Lambda表达式优化匿名内部类,但是两者之间的实现原理并不相同,所以不是“语法糖”的示例。
而增强for循环和迭代器的实现原理是一样的,可以使用增强for简化代码,这种写法便是“语法糖”,关键在于两者的实现原理是一样的。

三、Lambda表达式使用细节

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

凡是根据上下文推导出来的内容,都可以省略书写

可以省略的内容:

    1.(参数列表):括号中参数列表的数据类型,可以省略
    
    2.(参数列表):括号中的参数如果只有一个,那么类型和()都可以省略不写
    
    3.{一些代码}:如果{}中的代码只有一行,无论是否有返回值,都可以省略大括号{}、返回值return、分号;
    
注意:要省略{}、return和;的话,必须一起省略

Lambda的使用前提:

Lambda的语法非常简洁,完全没有面向对象复杂的束缚。

    1.使用Lambda必须具有接口,且要求【接口中有且仅有一个抽象方法】
    
      无论是JDK内置的Runnable、Comparator接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
      
    2.使用Lambda必须具有【上下文推断】
      也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例
      
备注:有且仅有一个抽象方法的接口,成为【”函数式接口“】