map方法
流支持map方法,接受一个函数作为参数。这个函数会被应用到每一个元素上,并将其映射成一个新的元素 。例如:Dish::getName 传给了map方法,用来提取菜肴的名称。getName 方法返回的是一个String,所以map方法输出的流
的类型就是Stream<String>。
// 获取名字的长度
@Test
public void testMap() {
ArrayList<String> words = Lists.newArrayList("java8", "Lambdas", "in");
List<Integer> collect = words.stream()
.map(String::length)
.collect(Collectors.toList());
Map<String, Integer> collect1 = words.stream().collect(Collectors.toMap(i -> i, i -> i.length()));
logger.info("words 长度是:{}", collect); //words 长度是:[5, 7, 2]
logger.info("collect1 map是:{}", collect1);//{Lambdas=7, in=2, java8=5}
}
flatMap方法
遇到的场景是,对于给定的单词表["hello","world"],你想要得到的是["H","e","l", "o","W","r","d"],单独的使用map方法
List<String[]> collect2 = words.stream()
.map(word -> word.split(""))
.distinct()
.collect(toList());
map实际上返回的是Stream<String[]>类型的, 但是真正想要的是Stream<String> 来表示一个字符流。使用map的图解
需要的是一个字符流,而不是数组流。又一个叫做Arrays.stream()的方法可以接受一个数并产生一个流。
可以使用flatMap来解决这个问题
使用flatMap的效果,各个数组不是分别映射成一个流,而是映射成流的内容。所有使用map(Arrays::stream)时生成的
单个流都被合并起来,既扁平化成一个一个流,图解如下:
一言以蔽之,flatMap方法会让给你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。
同样下面的这个图,对于flatMap的说明感觉很形象。
demo 练习
例如有以下的需求,一个字符串数组{"hello","word"},想得到所有的单个字符号["h","e","l","l","o","w","o","r","d"],会如何做呢?原来内容实现方法会这样:
@Test
public void testFlatMap() {
Gson gson = new Gson();
String[] helloStr = {"hello", "word"};
List<String> list = Lists.newArrayList();
Arrays.stream(helloStr)
.forEach(str -> {
List<String> collect1 = Arrays.stream(str.split("")).collect(Collectors.toList());
list.addAll(collect1);
});
logger.info("list 结果是:{}", gson.toJson(list));
//这是原来解决方法 (分层剥离,然后合并到一个list中去)
// list 结果是:["h","e","l","l","o","w","o","r","d"]
}
使用flatMap实现
@Test
public void testFlatMap() {
Gson gson = new Gson();
String[] helloStr = {"hello", "word"};
//分步写(流只能消费一次)(flatMap)
Stream<String[]> stream1 = Arrays.asList(helloStr).stream().
map(str -> str.split(""));
Stream<String> stringStream = stream1.flatMap(strings1 -> Arrays.stream(strings1));
List<String> stringList1 = stringStream.collect(Collectors.toList());
logger.info("结果是:{}", gson.toJson(stringList1));
//结果是:["h","e","l","l","o","w","o","r","d"]
//最后汇总写法
List<String> newList = Arrays.stream(helloStr)
.map(str -> str.split(""))
.flatMap(str -> Arrays.stream(str))
.collect(Collectors.toList());
logger.info("newList 结果是:{}", gson.toJson(newList));
//newList 结果是:["h","e","l","l","o","w","o","r","d"]
//https://www.cnblogs.com/java-le/p/7909729.html 讲解
}
嵌套两层的科目树等,结构如下:
[
{
"id":1,
"name":"河北",
"parent":0,
"children":[
{
"id":2,
"name":"邯郸",
"parent":1,
"children":[
{
"id":3,
"name":"成安",
"parent":2,
"children":[
]
}
]
}
]
},
{
"id":4,
"name":"北京",
"parent":0,
"children":[
{
"id":5,
"name":"北京市",
"parent":4,
"children":[
{
"id":6,
"name":"朝阳区",
"parent":5,
"children":[
]
}
]
}
]
}
]
获取最低级的县或者区的信息,使用flatMap获取
@Test
public void flatMap() {
Gson gson = new Gson();
List<TreeVo> treeVos = TreeVo.getTreeList();
System.out.println("所有的树结构是:{}" + gson.toJson(treeVos));
//所有的树结构是:[{"id":1,"name":"河北","parent":0,"children":[{"id":2,"name":"邯郸","parent":1,"children":[{"id":3,"name":"成安","parent":2,"children":[]}]}]},{"id":4,"name":"北京","parent":0,"children":[{"id":5,"name":"北京市","parent":4,"children":[{"id":6,"name":"朝阳区","parent":5,"children":[]}]}]}]
List<TreeVo> collect = treeVos.stream().flatMap(list ->
list.getChildren().stream().flatMap(vo -> vo.getChildren().stream())
).collect(Collectors.toList());
System.out.println("结果是:{}" + gson.toJson(collect));
//[{"id":3,"name":"成安","parent":2,"children":[]},{"id":6,"name":"朝阳区","parent":5,"children":[]}]
}
经常用的场景是List<list<T>>类型的结构,如下 List<List<StudentEntity>> 类型
/**
* List<List<StudentEntity>> 类型
*/
@Test
public void flatMapStudent() {
Gson gson = new Gson();
List<List<StudentEntity>> filterStudent = StudentEntity.getFilterStudent();
logger.info("filterStudent:{}", gson.toJson(filterStudent));
// filterStudent:[[{"userId":4,"userName":"第二个小红","age":4,"child":[]},{"userId":5,"userName":"第二个小花","age":5,"child":[]},{"userId":6,"userName":"第二个小黄","age":6,"child":[]}],[{"userId":1,"userName":"第一个小红","age":1,"child":[]},{"userId":2,"userName":"第一个小花","age":2,"child":[]},{"userId":3,"userName":"第一个小黄","age":3,"child":[]}]]
Set<String> collect = filterStudent.stream().flatMap(Collection::stream)
.map(StudentEntity::getUserName)
.collect(Collectors.toSet());
logger.info("结果是:{}", collect);
//结果是:[第二个小花, 第二个小红, 第二个小黄, 第一个小红, 第一个小花, 第一个小黄]
}
参考博客
https://www.cnblogs.com/diegodu/p/8794857.html
https://www.cnblogs.com/java-le/p/7909729.html
小结
主要是为了区分下,何时会使用flatMap,现在感觉是flatMap 适用于 List<List<object>> 这种类型的结果,数组里面包含一个数组,但是想获取object每个元素,可以使用这个