概述
map和flatMap API源于Java Stream流,在Java8中可以在Optional、Stream和CompletableFuture中找到相关用法。
Stream流表示一系列对象,而Optional表示对象存在或不存在的类,在不同的聚合操作中包括有map和flatMap方法。
Optional使用Map和Flatmap
map方法与Optional配合得很好,比如返回需要的确切类型:
Optional<String> s = Optional.of("test");
assertEquals(Optional.of("TEST"), s.map(String::toUpperCase));
使用map会导致嵌套结构,因为map实现会在内部进行额外的包装:
assertEquals(Optional.of(Optional.of("STRING")),
Optional
.of("string")
.map(s -> Optional.of("STRING")));
正如我们所看到的,最终得到了嵌套结构Optional<Optional<String>。虽然它可以工作,但使用起来相当麻烦,所以最好保持扁平化的结构。
这正是flatMap可以做到的:
assertEquals(Optional.of("STRING"), Optional
.of("string")
.flatMap(s -> Optional.of("STRING")));
Streams使用Map和Flatmap
map方法将底层序列封装在Stream实例中,而flatMap方法允许避免嵌套的Stream<Stream<R>>结构。
比如以下例子,map生成一个Stream,该Stream由将toUpperCase方法应用于输入Stream的元素组成:
List<String> myList = Stream.of("a", "b")
.map(String::toUpperCase)
.collect(Collectors.toList());
assertEquals(asList("A", "B"), myList);
map在这样一个简单的情况下工作得很好。但是,如果更复杂的比如一个包含多个列表的列表作为输入,让我们看看它是如何工作的:
List<List<String>> list = Arrays.asList(
Arrays.asList("a"),
Arrays.asList("b"));
System.out.println(list);
此片段打印:[[a],[b]]
现在让我们使用flatMap:
System.out.println(list
.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList()));
片段的结果将被扁平化为[a,b]。
flatMap方法首先将输入的多级Stream扁平化为同级Stream,之后,它的工作原理与map方法类似。
结论
Java 8为我们提供了使用map和flatMap方法,可以在Stream和Optional上进行元素转换处理,flatMap可以处理Collection数组扁平化。