一个非常常见的数据处理套路就是从某些对象中选择信息。比如在SQL里,你可以从表中选
择一列。Stream API也通过map和flatMap方法提供了类似的工具。
映射
1.map
流支持map方法,它会接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映 射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一 个新版本”而不是去“修改”)。
例如下面的例子,通过方法引用的方式获取学生名字:
class Test{
public static void main(String []args) {
List<Student> stuList = Arrays.asList(new Student("xiaoming",18),
new Student("xiaoli",22),
new Student("xiaozhang",19),
new Student("Tom",26),
new Student("Kevin",20),
new Student("Lucy",26)
);
Stream<String> nameStream = stuList.stream().map(Student::getName);
nameStream.forEach(System.out::println);
}
}
Output:
xiaoming
xiaoli
xiaozhang
Tom
Kevin
Lucy
因为getName方法返回一个String,所以map方法输出的流的类型就是Stream< String >.
再比如,获取到名字后还想获取每一个名字的长度:
Stream<Integer> nameStream = stuList.stream().map(Student::getName).map(String::length);
nameStream.forEach(System.out::println);
2.流的扁平化
如果我们写一个方法,用于接收字符串,并返回一个流
public static Stream<Character> filterCharacter(String str){ //接受String类型,返回一个流Stream<Character>
List<Character> list = new ArrayList<>();
for(Character ch : str.toCharArray()) { //将String类型的str变成character类型并用ch接收
list.add(ch);
}
return list.stream(); //返回一个list流
}
我们想获取List中的每个字母:
class Test{
public static void main(String []args) {
List<String> list =Arrays.asList("aa","bb","cc","dd");
//map()出来的就是流Stream<>,Test::filterCharacter方法出来的还是流Stream<Character>
Stream<Stream<Character>> stream1=list.stream().map(Test::filterCharacter);
//stream1的类型是Stream<Stream<Character>>,第一个forEach循环是外层Stream<>
stream1.forEach(sm ->{
sm.forEach(System.out::println);
});
}
Output:
a
a
b
b
c
c
d
d
通过这样的方式获取List中的每个字母有些麻烦,实际上是把两个流合在一起然后分别遍历出来的结果。但是通过flatmap的方法会简单很多:
Stream<Character> sm =list.stream().flatMap(Test::filterCharacter);
sm.forEach(System.out::println);
简而言之,flatmap方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。
例题:
给定两个数字列表,如何返回所有的数对呢?例如,给定列表[1, 2, 3]和列表[3, 4],应 该返回[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)]。为简单起见,你可以用有两个元素的数组来代 表数对。
List<Integer> numbers1 = Arrays.asList(1, 2, 3); List<Integer> numbers2 = Arrays.asList(3, 4); List<int[]> pairs =
numbers1.stream()
.flatMap(i -> numbers2.stream()
.map(j -> new int[]{i, j})
)
.collect(toList());