首先,看下map和flatMap的官方文档说明
其实单纯的看api说明还是比较抽象,下面我将以几个实战例子来帮助我们理解。然后再回过头来看它的说明,就会有一种恍然大悟的感觉。
字母大小写
public static void main(String[] args) throws Exception {
// 将集合中的所有的小写字母转为大写字母
List list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
list.add("python");
List result = list.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println(result);
}
输出结果如下:
[HELLO, WORLD, JAVA, PYTHON]
平方数
public static void main(String[] args) throws Exception {
// 求集合中每个元素的平方数
List nums = Arrays.asList(1, 2, 3, 4);
List result = nums.stream().map(n -> n * n).collect(Collectors.toList());
System.out.println(result);
}
输出结果如下:
[1, 4, 9, 16]
从上面例子可以看出,map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。还有一些场景,是一对多映射关系的,这时需要 flatMap。
单词提取
public static void main(String[] args) throws Exception {
// 将集合中的字符串中单词提取出来,不考虑特殊字符
List words = Arrays.asList("hello c++", "hello java", "hello python");
List result = words.stream()
// 将单词按照空格切合,返回Stream类型的数据
.map(word -> word.split(" "))
// 将Stream转换为Stream
.flatMap(Arrays::stream)
// 去重
.distinct()
.collect(Collectors.toList());
System.out.println(result);
}
输出结果如下:
[hello, c++, java, python]
元素抽取
public class Main {
public static void main(String[] args) throws Exception {
// 初始化测试数据
List hobby1 = Arrays.asList("java", "c", "音乐");
List hobby2 = Arrays.asList("c++", "c", "游戏");
User user1 = new User(1, "张三", hobby1);
User user2 = new User(2, "李四", hobby2);
ArrayList users = new ArrayList<>();
users.add(user1);
users.add(user2);
// 将集合中每个用户的爱好进行计算,取并集
List result = users.stream()
.map(user -> user.hobby)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
System.out.println(result);
}
static class User {
int id;
String name;
List hobby;
public User(int id, String name, List hobby) {
this.id = id;
this.name = name;
this.hobby = hobby;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return id == user.id &&
Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + ''' +
'}';
}
}
}
输入结果如下:
[java, c, 音乐, c++, 游戏]
flatMap 把 input Stream 中的层级结构扁平化,就是将最底层元素抽出来放到一起,最终 output 的新 Stream 里面已经没有 List 了,都是直接的数字.
对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种方法,可以免除自动装箱/拆箱的额外消耗。
和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中。