Java8中map()和flatMap()的區別
阿新 • • 發佈:2021-06-20
綜述
map()和flatMap()源自於函式式語言,在Java 8中,我們可以在Optional、Stream和CompletableFuture中找到它們(雖然名字稍有不同)。
stream表示一個物件序列,而optionals表示一個值可以是存在的,也可以是不存在的,在其他aggregate操作中,有map()和flatMap()方法。
儘管兩者具有相同的返回型別,但它們是完全不同的。
Optionals中的Map和FlatMap
如果函式返回的正是我們需要的確切型別,那麼map()方法可以很好的在Optional中使用。
Optional<String> s = Optional.of("test"); assertEquals(Optional.of("TEST"), s.map(String::toUpperCase));
然而,在更復雜的情況下,我們可能會得到一個返回Optional的函式。在這種情況下,使用map()會導致巢狀結構,因為map()實現在內部進行了額外的包裝。
assertEquals(Optional.of(Optional.of("STRING")),
Optional
.of("string")
.map(s -> Optional.of("STRING")));
通過map我們得到了一個巢狀的結構,儘管它可以工作,但使用起來相當繁瑣,而且沒有提供任何額外的null安全性,所以最好應該保持flat的資料結構。
assertEquals(Optional.of("STRING"), Optional .of("string") .flatMap(s -> Optional.of("STRING")));
Stream中的Map和Flatmap
map()方法將底層序列包裝在Stream例項中,而flatMap()方法可以避免巢狀的Stream<Stream<R>>結構。
map()生成一個流,其中包含對輸入流的元素應用toUpperCase()方法的結果
List<String> myList = Stream.of("a", "b")
.map(String::toUpperCase)
.collect(Collectors.toList());
assertEquals(asList("A", "B"), myList);
如下為將一個列表的列表作為輸入:
List<List<String>> list = Arrays.asList(
Arrays.asList("a"),
Arrays.asList("b"));
System.out.println(list);
//output: [[a], [b]]
使用flatMap,結果將扁平化為 [a,b]
System.out.println(list
.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList()));
flatMap()方法首先將list輸入流扁平化為字串流,此後它的工作方式類似於map()。
扁平化巢狀的集合
巢狀集合的示例
假設有一個String型別列表的列表:
List<List<String>> nestedList = asList(
asList("one:one"),
asList("two:one", "two:two", "two:three"),
asList("three:one", "three:two", "three:three", "three:four"));
用forEach扁平化List
為了將這個巢狀集合扁平化為一個字串列表,可以將forEach與Java 8方法引用一起使用
public <T> List<T> flattenListOfListsImperatively(
List<List<T>> nestedList) {
List<T> ls = new ArrayList<>();
nestedList.forEach(ls::addAll);
return ls;
}
@Test
public void givenNestedList_thenFlattenImperatively() {
List<String> ls = flattenListOfListsImperatively(nestedList);
assertNotNull(ls);
assertTrue(ls.size() == 8);
assertThat(ls, IsIterableContainingInOrder.contains(
"one:one",
"two:one", "two:two", "two:three", "three:one",
"three:two", "three:three", "three:four"));
}
用flatMap扁平化List
還可以利用Stream API中的flatMap方法使巢狀列表扁平化,這個方法允許我們扁平巢狀的Stream結構,並最終將所有元素收集到一個特定的集合中。
public <T> List<T> flattenListOfListsStream(List<List<T>> list) {
return list.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
@Test
public void givenNestedList_thenFlattenFunctionally() {
List<String> ls = flattenListOfListsStream(nestedList);
assertNotNull(ls);
assertTrue(ls.size() == 8);
}