Lambda匿名函数表达式
- 最主要的特点:可以将函数作为参数传入方法
实际上,Lambda表达式主要用于实现接口(只有一个待实现方法的接口),比如
Runnable
接口,内部只有run()
方法待实现,那么就可以用Lambda表达式实现Runnable
接口:
Runnable run = () -> System.out.println("run")
Thread t = new Thread(() ->System.out.println("run"))
的方式来实现Thread,而不是古老的显式Override的方式。Lambda可以利用编译器做很多自动推理的工作,例如传参、返回值、类型等信息都可以通过编译器自动推理得出,所以在编写的时候可以省略很多东西。例如:
1 | List<Integer> list = new ArrayList<>(Arrays.asList(4, 2, 6, 1)); |
上例中,实际是用(a, b) -> a - b
实现了Comparator接口,编译器自动推理出了a和b的类型,以及实现接口的类型,以及省略了return
方法引用
方法引用,可以理解为Lambda的一种简化版,用法是class::method或object::method,方法引用可以分为4类
- 引用静态方法,ClassName::staticMethod,例如:String::valueOf,对应的Lambda就是(s) -> String.valueOf(s)
- 引用对象实例的方法,object::method,例如:”a”.toString,对应的Lambda就是 () -> this.toString()
- 引用特定类型的任意对象的方法,Class::method,例如:String::toString,对应的Lambda就是 (s) -> s.toString
- 引用构造函数,Class::new,例如:String::new,对应的Lambda是() -> new String()
方法引用示例
假设有个接口:
1 | private static interface Inter { |
静态方法引用:Inter inter = String::valueOf;
等效于:inter inter = (a) -> String.valueOf(a);
引用特定类型的任意对象方法:inter inter = String::toString;
等效:inter inter = (a) -> a.toString;
引用对象实例的方法:inter inter = “test”::toString
; 等效:inter inter = () -> “test”.toString;
引用构造方法:inter inter = String::new
; 等效:inter inter = (a) -> new String(a);
个人认为,先理解了Lambda,再用Lambda来理解方法引用,会更加容易理解
函数式接口
根据上述描述可知,Lambda表达式以及方法引用,实际上都是为了实现接口的,而能被实现的接口都有一个共同点,就是只有一个待实现方法。在Java8中,这种接口被统一称为函数式接口。
在Java8之前,其实就存在了很多这样的接口,比如Runnable、Comparator、InvocationHandler等,在JDK1.8中还加入了java.util.function包,内含有大量的函数式接口可供使用,而Java已经给JDK中所有的函数式接口都加上了@FunctionalInterface接口,来标注这是一个函数式接口
默认方法
Java8中,为每个接口提供了一种可以实现默认方法的机制,定义方法时,在前面加上default就可以了,之后实现这个接口的类都会继承这个默认方法(除非重写了此方法)
另外,还提供了一种静态默认方法,即每个接口都可以实现一个静态方法,之后就可以像类一样,通过接口名直接调用该方法。
例如:
1 | public interface Inter { |
Stream
流是一种新的对象,是Java8的新特性之一
对流的操作可以简化为产生流对象->对流进行操作->收集流对象
的流程
产生流对象
可以通过Stream的静态方法、Collection的stream()、parallelStream()方法、Arrays.stream(数组)等方式产生一个流对象
对流进行操作
- filter:设置过滤条件,会返回流,如:stream.filter(a -> a % 2 == 0)
- forEach: 迭代流中的每个元素进行操作,如:stream.forEach(System.out::println)
- map:对每一个元素做映射,会返回一个流,如:stream.map(i -> i + 1)
- limit:截取流的一部分,返回流对象,如:stream.limit(2)
- sort:对流进行排序,返回流对象,可以带入Comparator自定义排序方式,如:stream.sorted((a, b) -> b-a).forEach(System.out::println),这是将流逆序排序后输出
- 等等等….
重新收集流对象
收集是为了将流转换回正常POJO对象
- count:顾名思义,即返回流中对象的数量
- collect:特别重要,多数流对象是由集合转换来的,所以最后多数也要转换回集合类型,即可以用collect将流中的对象收集并转换为集合。如:stream.collect(Collectors.toList)、stream.collect(Collectors.toSet)、stream.collect(Collectors.toMap(i -> i, i -> i * i))……,在Collectors类中有很多静态方式可供使用
示例:
1 | public static void main(String[] args) { |
Optional
Java8引入了Optional类主要是为了解决null
Optional对象的生成:
1 |
|
Optional对象的操作:
1 |
|
其他特性
Nashorn, JavaScript 引擎
新的日期API,不需要使用Date+Calendar对日期操作
Java8内置了Base64的编码器和解码器
不再一一赘述