JDK8新特性


Lambda表达式

lambda表达式是Java8新增特性,它可以用来简化匿名内部类的写法。注意:Lambda表达式只能简化函数式接口的匿名内部类的写法形式(lambda表达式是一个函数式接口的实例:只要一个对象时函数式接口的实例,那么该对象就可以用lambda表达式来表示,所以以前使用匿名实现类表示的现在都可以用lambda表达式来写)

lambda表达式的简化格式

(匿名内部类被重写方法的形参列表) -> {
    被重写方法的方法体代码
}

lambda表达式的使用,分六种情况介绍:

// 情况一:无参,无返回值
Runnable r = () -> {
    System.out.println("hello world");
};

// 情况二:需要一个参数,但没有返回值
Consumer con = (String s) -> {
    System.out.println("hello world");
};

// 情况三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
Consumer con = (s) -> {
    System.out.println("hello world");
};

// 情况四:若lambda只需要一个参数时,参数的小括号可以省略
Consumer con = s -> {
    System.out.println("hello world");
};

// 情况五:若lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
Comparator com = (x, y) -> {
    System.out.println(x + " " + y);
    return x.compareTo(y);
};

// 情况六:若lambda方法体中只有一条语句时,return与大括号都可省略
Comparator com = (x, y) -> x.compareTo(y);

函数式接口

lambda表达式的目标类型必须是"函数式接口",函数式接口代表只包含一个抽象方法的接口。函数式可接口可以包含多个默认方法、类方法,但只能声明一个抽象方法。在函数式接口上都有一个 @FunctionalInterface 注解,该注解用于告诉编译器执行更严格检查——检查该接口必须是函数式接口,否则编译器就会报错

java.util.function 包下预定义了大量函数式接口,如以下四类核心接口:

函数式接口 包含方法 返回值类型 用途
Function
函数型接口
apply(T t) R 对参数进行处理转换,然后返回一个新的值
Consumer
消费型接口
accept(T t) void 消费数据;对参数进行处理,不会返回处理结果
Predicate
断定型接口
test(T t) boolean 对参数进行某种判断,然后返回一个boolean值
Supplier
供给型接口
get() T 生产数据;该方法不需要传入参数,它会返回一个类型为T的对象

方法引用和构造器引用

如果lambda表达式的代码只有一条,还可以在代码块中使用方法引用和构造器引用

实例 说明
类名::静态方法 函数式接口中被实现方法的全部参数传给该类方法作为参数
对象::实例方法 函数式接口中被实现方法的全部参数传给该方法作为参数
类名::实例方法 函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数
类名::new 函数式接口中被实现方法的全部参数传给该构造器作为参数
  • 可以在方法引用中使用this、super参数,例如this::equals等同于x->this.equals(x)

Stream接口

Stream API(java.util.stream)把真正的函数式编程风格引入到Java中,提供了一种高效且易于使用的处理数据的方式。它可以对集合进行操作,例如执行非常复杂的查找、过滤和映射数据等操作
集合讲的是数据,Stream讲的是计算

  • Stream不会自己存储元素
  • Stream不会改变原对象,它们会返回一个持有结果的新Stream
  • Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行

Stream操作的三个步骤:

  1. 创建Stream:根据一个数据源(如集合/数组),获取一个流
  2. 中间操作:对数据源的数据进行处理
  3. 终止操作:一旦执行终止操作,就执行中间操作链,并产生结果。之后不会再被使用

创建Stream流对象

  • 方法一:通过集合,Collection中有一个默认的stream()方法
    • default Stream stream():返回一个顺序流
    • default Stream parallelStream():返回一个并行流
  • 方法二:通过数组,Arrays中有一个静态stream()方法
    • static Stream stream(T[] array):返回一个流
  • 方法三:通过Stream接口的静态方法of()返回一个流
  • 方法四:创建无限流;通过Stream接口的静态方法iterator和generate()方法
    • 迭代:static Stream iterate(final T seed,final UnaryOperator f)
    • 生成:static Stream generate(Supplier s)

Stream的中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会自行任何的处理。而在终止操作时一次性全部处理,称为“惰性求值”

筛选和切片 说明
filter(Predicate p) 从流中排除某些元素
distinct() 去重
limit(long maxSize) 使元素不超过给定的数量
skip(long n) 跳过元素
映射 说明
map(Function f)
mapToDouble(ToDoubleFunction f)
mapToInt(ToIntFunction f)
mapToLong(ToLongFunction f)
flatMap(Function f)
排序 说明
sorted() 按自然顺序排序
sorted(Comparator com) 按比较器顺序排序

终止操作

终止操作会从流的流水线生成结果。流终止操作后,不能再次使用

匹配与查找 说明
allMatch(Predicate p) 检查是否匹配所有的元素
anyMatch(Predicate p) 检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
forEach(Consumer c) 内部迭代
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
count() 返回流中元素总数
归约 说明
reduce(T iden,BinaryOperator b) 将流中元素反复结合起来,得到一个值
reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值

补充:map和reduce的连接通常称为map-reduce模式,Google用它来进行网络搜索而出名

收集 说明
collect(Collector c) 将流转换为其他形式

Collectors提供了很多静态方法,可以方便地创建常见集合实例

Optional类

空指针异常时导致Java应用程序失败的最常见原因,JDK8引入Optional类来检查空值,防止代码污染

Optional类(java.util.Optional)是一个容器类

……待续