上节我们已经明白了Lambda表达式是通过函数接口实现的,JDK 1.8 API 包含了很多内建的函数接口,有一些是为了老版本如Comparator or Runnable. 这些已经存在的接口都做了拓展,通过 @FunctionalInterface 注解以便更好地支持Lambda。
但是在Java 8中还有一些新的函数接口让你开发更简单,一些新的接口来自于google的 Guava库。
内建函数接口
Predicates
Predicates是一个只有一个参数的返回boolean值的函数 这个接口包含了各种默认方法,用来组合predicates完成复杂的逻辑表达(and, or, negate)
//只有一个输入参数s,返回的是非真即否的boolean类型
Predicate<String> predicate = (s) -> s.length() > 0; predicate.test("foo"); // true predicate.negate().test("foo"); // false Predicate<Boolean> nonNull = Objects::nonNull; Predicate<Boolean> isNull = Objects::isNull; Predicate<String> isEmpty = String::isEmpty; Predicate<String> isNotEmpty = isEmpty.negate();
Functions
Functions 接受一个输入参数,产生一个结果,默认方法能被多个函数一起作为链条一样使用 (compose, andThen).
Function<String, Integer> toInteger = Integer::valueOf; Function<String, String> backToString = toInteger.andThen(String::valueOf); backToString.apply("123"); // "123"
Suppliers
Suppliers 产生一个给定泛型类型的结果,不像Functions, Suppliers并不接受输入参数。
Supplier<Person> personSupplier = Person::new; personSupplier.get(); // new Person
Consumers
Consumers是对单个输入参数执行的一些操作。
Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName); greeter.accept(new Person("Luke", "Skywalker"));
Comparators
Comparators是老版本比较器在Java8应用,Java 8加了默认方法,可以作为Lambda表达式使用,不再需要以前老式专门做一个Comparator实现类了。
Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName); Person p1 = new Person("John", "Doe"); Person p2 = new Person("Alice", "Wonderland"); comparator.compare(p1, p2); // > 0 comparator.reversed().compare(p1, p2); // < 0
Optionals
Optionals并不是函数接口,它是一个能够阻止空指针错误NullPointerException小巧的工具。
Optional是一个值容器,这个值可以是空或不空。过去我们一个方法应该返回不空的值,但是可能返回空,那么现在我们可以使用Java 8,返回一个Optional即可
Optional<String> optional = Optional.of("bam"); optional.isPresent(); // true optional.get(); // "bam" optional.orElse("fallback"); // "bam" optional.ifPresent((s) -> System.out.println(s.charAt(0))); // "b"
Streams
java.util.Stream代表一个序列元素,这些元素能够执行一个或多个操作, Stream操作既可以是intermediate 或者terminal. 而terminal操作返回某个类型的一个结果, intermediate 操作返回的是stream自身,这样你能将多个调用链接在一行中实现。Streams是被一个源 如一个java.util.Collection 类似lists 或 sets 创建(maps还没有支持). Stream 操作可以顺序也可以并行实现。
为了看看顺序操作是如何执行的,我们首先创建如下源:
List<String> stringCollection = new ArrayList<>(); stringCollection.add("ddd2"); stringCollection.add("aaa2"); stringCollection.add("bbb1"); stringCollection.add("aaa1"); stringCollection.add("bbb3"); stringCollection.add("ccc"); stringCollection.add("bbb2"); stringCollection.add("ddd1");
这是一个字符串集合。在Java 8中中集合Collections已经被拓展,你能简单地调用 Collection.stream() 或 Collection.parallelStream()来创建Stream.下面解释 Stram的主要操作。
Filter
Filter接受一个predicate,然后根据其返回真或假对Stram中所有元素进行过滤,这个操作是intermediat,所以能让我们对结果再调用其他stream操作(如forEach)处理. ForEach能接受对 stream每个元素执行函数操作 (这个例子中是filtered). ForEach是一个terminal操作. 它返回 void, 这样我们不能基于其结果再调用其他Stram操作了。
stringCollection .stream() .filter((s) -> s.startsWith("a")) .forEach(System.out::println); // "aaa2", "aaa1"
Sorted
Sorted是一个intermediate操作,能够返回Stream的排序结果,元素是按自然排序规则,除非你传入一个定制的Comparator.
stringCollection .stream() .sorted() .filter((s) -> s.startsWith("a")) .forEach(System.out::println); // "aaa1", "aaa2"
请记住已经排序意味着创建一个排过许的视图,并不会在后端真正产生一个的排序集合,stringCollection中的元素顺序其实没有变化:
System.out.println(stringCollection); // ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1
Map
Map操作也是intermediate的,按给定的函数对每个元素转换操作到一个结果。下面案例是使用函数转换字符串到大写将每个输入字符串转到到大写字符。
stringCollection .stream() .map(String::toUpperCase) .sorted((a, b) -> b.compareTo(a)) .forEach(System.out::println); // "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
你也可以使用map转换一个对象到另外一个类型,Stream的结果的泛型类型取决于你传入函数的泛型类型。
Match
各种匹配操作能够用于检测某个predicate是否匹配stream. 所有这些操作都是terminal,不能再被用作Stream其他操作的输入了,并且只返回一个boolean结果
boolean anyStartsWithA = stringCollection .stream() .anyMatch((s) -> s.startsWith("a")); System.out.println(anyStartsWithA); // true boolean allStartsWithA = stringCollection .stream() .allMatch((s) -> s.startsWith("a")); System.out.println(allStartsWithA); // false boolean noneStartsWithZ = stringCollection .stream() .noneMatch((s) -> s.startsWith("z")); System.out.println(noneStartsWithZ); // true
Count
Count是一个terminal操作,返回Stream中元素的个数,类型是初始类型long.
long startsWithB = stringCollection .stream() .filter((s) -> s.startsWith("b")) .count(); System.out.println(startsWithB); // 3
Reduce
这个terminal操作执行对Stream元素按给定函数执行约简的操作,结果是包含约简好的元素的一个Optional。
Optional<String> reduced = stringCollection .stream() .sorted() .reduce((s1, s2) -> s1 + "#" + s2); reduced.ifPresent(System.out::println); // "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"