实际上,Lambda表达式主要用于实现接口(只有一个待实现方法的接口),比如Runnable
接口,内部只有run()
方法待实现,那么就可以用Lambda表达式实现Runnable
接口:
Runnable run = () -> System.out.println("run")
Thread t = new Thread(() ->System.out.println("run"))
的方式来实现Thread,而不是古老的显式Override的方式。
Lambda可以利用编译器做很多自动推理的工作,例如传参、返回值、类型等信息都可以通过编译器自动推理得出,所以在编写的时候可以省略很多东西。例如:
List list = new ArrayList<>(Arrays.asList(4, 2, 6, 1));
list.sort(((a, b) -> a - b));
上例中,实际是用(a, b) -> a - b
实现了Comparator接口,编译器自动推理出了a和b的类型,以及实现接口的类型,以及省略了return
方法引用,可以理解为Lambda的一种简化版,用法是class::method或object::method,方法引用可以分为4类
假设有个接口:
private static interface Inter {
String test(String a);
//引用对象实例的方法时,去掉String
}
静态方法引用: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就可以了,之后实现这个接口的类都会继承这个默认方法(除非重写了此方法)
另外,还提供了一种静态默认方法,即每个接口都可以实现一个静态方法,之后就可以像类一样,通过接口名直接调用该方法。
例如:
public interface Inter {
String test(String a);
default void test2() {
System.out.println("Default");
}
static void test3() {
System.out.println("Static");
}
}
流是一种新的对象,是Java8的新特性之一
对流的操作可以简化为产生流对象->对流进行操作->收集流对象
的流程
可以通过Stream的静态方法、Collection的stream()、parallelStream()方法、Arrays.stream(数组)等方式产生一个流对象
收集是为了将流转换回正常POJO对象
示例:
public static void main(String[] args) {
Stream stream = Stream.of(3, 4, 1, 9, 6, 2, 8, 7, 0); // 生成流对象
// 逆序排序后截取前5个并返回列表
List list = stream.sorted((a, b) -> b - a).limit(5).collect(Collectors.toList());
// 过滤出所有奇数,并以自己为key,平方为value存入map中
Map map = stream.filter((x) -> x % 2 == 1).collect(Collectors.toMap((i) -> i, (i) -> i * i));
// 返回流中对象的个数
Long count = stream.count();
}
Java8引入了Optional类主要是为了解决null
Optional对象的生成:
// 不能放入null
Optional optional = Optional.of("optional");
// 可以放入null
optional = Optional.ofNullable(null);
// 只能是null
optional = Optional.empty;
Optional对象的操作:
optional.get(); // 如果非null则返回对象,如果是null则抛出NoSuchElementException异常
optional.isPresent(); //如果非null返回true,是null则返回false
// 下面两句的效果是一样的
optional.ifPresent(System.out::println);
if(optional.isPresent()) {
System.out.println(optional.get());
}
optional.orElse(""); //如果为null则返回传入的对象,否则返回内部的对象
optional.orElseGet(String::new); //如果为null则返回supplier.get, supplier则为传入的接口
optional.orElseThrow(exceptionSupplier); //如果为null则抛出exceptionSupplier.get,这是一个异常生成的接口
optional = optional.map((s) -> s + "!"); //如果不为null,则对内部的对象做一个映射并返回Optional对象,如果为null则返回空Optional对象
optional = optional.flatMap((s) -> Optional.of(s + "!")); //和map不同的一点是,flatMap传入的接口必须返回Optional对象,而map会自动封装
optional = optional.filter((s) -> s.length() > 6);// 有点像Stream的filter函数,但是不同的是,Stream中包含了大量元素,因此多数时候会有剩下的,但是Optional的filter更像是断言,true则原样返回,false则返回空Optional对象
Nashorn, JavaScript 引擎
新的日期API,不需要使用Date+Calendar对日期操作
Java8内置了Base64的编码器和解码器
不再一一赘述