1. Lambda表达式
函数式编程思想概述
在数学中,函数就是有输入量,输出量的一套计算方案,也就是"拿数据做操作"
面向对象思想强调"必须通过对象的形式来做事情"
函数式思想则尽量忽略面向对象的复杂语句:"强调做什么,而不是以什么形式去做"
而Lambda表达式就是函数式思想的体现
Lambda表达式的标准格式
匿名内部类中重写run()方法的代码分析
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("多线程程序启动了");
}
}).start();
①方法形式参数为空,说明调用方法时不需要传递参数
②方法返回值类型为void,说明方法执行没有结果返回
③方法体中的内容,是我们具体要做的事情
Lambda表达式的代码分析
new Thread(()->{
System.out.println("多线程程序启动了");
}).start();
( ):里面没有内容,可以看成是方法形式参数为空
->:用箭头指向后面要做的事情
{ }:包含一段代码,我们称之为代码块,可以看成是方法体中的内容
组成Lambda表达式的三要素:形式参数,箭头,代码块
Lambda表达式的标准格式
Lambda表达式的格式
格式:(形式参数) ->{代码块}
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
->:由英文中画线和大于符号组成,固定写法。代表指向动作
代码块:是我们具体要做的事情,也就是以前写的方法体内容
Lambda表达式的使用前提
①有一个接口
②接口中有且仅有一个抽象方法
Lambda表达式的省略模式
省略规则:
①参数类型可以省略。但是有多个参数的情况下,不能只省略一个
②如果参数有且仅有一个,那么小括号可以省略
③如果代码块的语句只有一条,可以省略大括号和分号,甚至是return
Lambda表达式的注意事项
注意事项:
①使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法
②必须有上下文环境,才能推导出Lambda对应的接口
根据局部变量的赋值得知Lambda对应的接口:Runnable r = () ->System.out.println("Lambda表达式");
根据调用方法的参数得知Lambda对应的接口:new Thread(() ->System.out.println("Lambda表达式")).start();
Lambda表达式和匿名内部类的区别
所需类型不同
①匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
②Lambda表达式:只能是接口
使用限制不同
①如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
②如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
实现原理不同
①匿名内部类:编译之后,产生一个单独的.class字节码文件
②Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
2.接口组成更新
接口组成更新概述
接口的组成
①常量
public static final
②抽象方法
public abstract
③默认方法(Java8)
④静态方法(Java8)
⑤私有方法(Java9)
接口中默认方法
接口默认方法的定义格式
格式:
public default 返回值类型 方法名(参数列表){ }
范例:
public default void show(){ }
接口中默认方法的注意事项:
①默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
②public可以省略,default不能省略
接口中静态方法
接口中静态方法的定义格式:
格式:
public static 返回值类型 方法名(参数列表){ }
范例:
public static void show(){ }
接口中静态方法的注意事项:
①静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
②public可以省略,static不能省略
接口中私有方法
Java9中新增了带方法体的私有方法,这其实在Java8中就埋下了伏笔:Java8允许在接口中定义带方法体的默认方法和静态方法。这样可能就会引发一个问题:当两个默认方法或者静态方法中包含同一段相同的代码实现时,程序必然考虑将这段实现代码抽取成一个共性方法,而这个共性方法是不需要让别人使用的,因此用私有给隐藏起来,这就是Java9增加私有方法的必然性
接口中私有方法的定义格式
格式1:
private 返回值类型 方法名(参数列表){ }
范例1:
private void show(){ }
格式2:
private static 返回值类型 方法名(参数列表){ }
范例2:
private static void method(){ }
接口中私有方法的注意事项:
①默认方法可以调用私有的静态方法和非静态方法
②静态方法只能调用私有的静态方法
3.方法引用
方法引用符
::该符号为引用运算符,而它所在的表达式被称为方法引用
Lambda表达式:
usePrintable(s -> System.out.println(s));
分析:拿到参数s之后通过Lambda表达式,传递给System.out.println方法去处理
方法引用:
usePrintable(System.out::println);
分析:直接使用System.out中的println方法来取代Lambda,代码更加的简洁
推导与省略
①如果使用Lambda,那么根据"可推导就是可省略"的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导
②如果使用方法引用,也是同样可以根据上下文进行推导
③方法引用是Lambda的孪生兄弟
Lambda表达式支持的方法引用
常见的引用方式:
引用类方法
引用对象的实例方法
引用类的实例方法
引用构造器
引用类方法
引用类方法,其实就是引用类的静态方法
格式:
类名::静态方法
范例:
Integer::parseInt
Integer类的方法:
public static int parseInt(String s)
将此String转换为int类型数据
Lambda表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数
引用对象的实例方法
引用对象的实例方法,其实就是引用类中的成员方法
格式:
对象::成员方法
范例:
"HelloWorld"::toUpperCase
String类中的方法:
public static toUpperCase()
将此String所有字符都转换为大写
Lambda表达式被对象的实例方法替代的时候,它的形式参数全部传递给该方法作为参数
引用类的实例方法
引用类的实例方法,其实就是引用类中的成员方法
格式;
类名::成员方法
范例:
String::substring
String类中的方法:
public String substring(int beginIndex,int endIndex)
从beginIndex开始到endIndex结束,截取字符串。返回一个子串,字串的长度为endIndex-beginIndex
Lambda表达式被类的实例方法替代的时候
①第一个参数作为调用者
②后面的参数全部传递给该方法作为参数
引用构造器
引用构造器,其实就是引用构造方法
格式:
类名::new
范例:
Student::new
Lambda表达式被构造器替代的时候,它的形式参数全部传递给构造器作为参数