** 注意** :list.stream()中的.stream()是将list集合展开,分割成一个一个
1:中间操作
一个流可以后面跟随零个或多个中间操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的,仅仅调用到这类方法,并没有真正开始流的遍历,真正的遍历需等到终端操作时,常见的中间操作有下面即将介绍的 filter、map 等。
2:终端操作
一个流有且只能有一个终端操作,当这个操作执行后,流就被关闭了,无法再被操作,因此一个流只能被遍历一次,若想在遍历需要通过源数据在生成流。终端操作的执行,才会真正开始流的遍历。如下面即将介绍的 count、collect 等。
public static void main(String[] args) {
List<Map<String, Integer>> list = new ArrayList<>();
Map<String, Integer> map1 = new HashMap<>();
map1.put("aa", 1);
map1.put("bb", 2333);
map1.put("cc", 3);
list.add(map1);
Map<String, Integer> map2 = new HashMap<>();
map2.put("aa", 1);
map2.put("bb", 22);
map2.put("cc", 23);
list.add(map2);
Map<String, Integer> map3 = new HashMap<>();
map3.put("aa", 31);
map3.put("bb", 32);
map3.put("cc", 33);
list.add(map3);
System.out.println(list);
Set<String> chartSet=list.stream().filter(a->a.get("aa").equals(1)).map(d->d.get("bb").toString()).collect(Collectors.toSet());
System.out.println(chartSet);
}
打印结果是
[{aa=1, bb=2333, cc=3}, {aa=1, bb=22, cc=23}, {aa=31, bb=32, cc=33}]
[22, 2333]
List<<Map<String, Object>> newList = list.stream().map(d -> {
d.put("user","李四");
d.put("age", "18");
return d;
}).collect(Collectors.toList());
List<Map<String, Object>> collect = listData.stream().map(dd -> {
dd.get("name");
dd.get("chanel");
return dd;
}).collect(Collectors.toList());
System.out.println(collect);
通过distinct方法快速去除重复的元素
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
List<Integer> stream = integerList.stream().distinct().collect(Collectors.toList());
System.out.println(stream);
打印结果是
[1, 2, 3, 4, 5]
flatMap()的作用是对流中的元素进行1对多的转换,然后将结果元素展开为新的流。
这句话的含义是什么?你可以理解为flatMap就是两层for循环处理数据。而返回结果就是flatMap展开的流。
/**
* 玩具类
*/
@Data
@AllArgsConstructor
public class Toy {
private String name;
private double price;
}
-----------------------------------------------------------------------------------------------------------------
@Data
@AllArgsConstructor
public class Boy {
private String name;
private int age;
private List<Toy> toys;
}
-----------------------------------------------------------------------------------------------------------------
@Data
@AllArgsConstructor
public class Student {
private String name;
private String schoolName;
private String className;
}
-----------------------------------------------------------------------------------------------------------------
public class TestStream {
private static List<Boy> boys = new ArrayList<>();
private static List<Student> stus = new ArrayList<>();
static {
boys.add(new Boy("tom", 12,
Arrays.asList(
new Toy("飞机", 9.1),
new Toy("坦克", 7.0),
new Toy("小熊", 14.0))));
boys.add(new Boy("tony", 19,
Arrays.asList(
new Toy("玩具枪", 13.1),
new Toy("小汽车", 12.2))));
stus.add(new Student("tom", "衡水中学", "尖子班"));
stus.add(new Student("jerry", "黄冈中学", "普通班"));
stus.add(new Student("dom", "衡水一中", "文科班"));
}
}
其等效于两层for循环,最终得到的结果是n*m给元素。(注:n是外层循环次数,m是内层循环次数)
public static void main(String[] args) {
//此时是处理第二个循环
List<Toy> toys = boys.stream().flatMap(
//将流中元素的数据再次展开
b -> b.getToys().stream()).
collect(Collectors.toList());
System.out.println(JSON.toJSONString(toys));
// 等效于
//因为是1:n的关系,所以最终会产生n记录
List<Toy> tls = new ArrayList<>();
for (Boy boy : boys) {
for (Toy toy : boy.getToys()) {
tls.add(toy);
}
}
//打印数据
System.out.println(JSON.toJSONString(tls));
}
当然在flatMap方法内部,可以利用这两个流的元素进行操作。
public static void main(String[] args) {
List<String> collect1 = boys.stream().flatMap(b -> b.getToys().stream().
filter(t -> t.getPrice() > 12).
map(t -> {
//即可以操作外层元素也可以操作内层元素
return b.getName() + ":" + t.getName();
})).collect(Collectors.toList());
System.out.println(JSON.toJSONString(collect1));
//等效于:
List<String> tls1 = new ArrayList<>();
for (Boy boy : boys) {
for (Toy toy : boy.getToys()) {
if (toy.getPrice() > 12) {
tls1.add(boy.getName() + ":" + toy.getName());
}
}
}
System.out.println(JSON.toJSONString(tls1));
}
}
而flatMap()操作的一个作用就是将两个集合合并为一个集合,相当于join操作,若没有filter操作,会产生笛卡尔积现象
public static void main(String[] args) {
List<String> collect = boys.stream().flatMap(b -> stus.stream().
//第二层for循环中处理数据
filter(s -> b.getName().equals(s.getName())).
//将数据放入到一个新的集合中
map(Student::getName)
//结束第二层循环
).collect(Collectors.toList());
System.out.println(JSON.toJSONString(collect));
//等效于
List<String> data=new ArrayList<>();
//双层for循环处理数据
for (Boy boy : boys) {
for (Student student : stus) {
//filter条件
if(boy.getName().equals(student.getName())){
//map子句,将元素放入到新集合中
data.add(student.getName());
}
}
}
System.out.println(JSON.toJSONString(data));
}
总结:JDK1.8提供了Stream提供的流式操作可以使得开发人员像操作数据库一样操作集合。Map相当于select映射,而flatMap更像join连接
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FlatMap {
public static void main(String[] args) {
//扁平化流
//找出数组中唯一的字符
String[] strArray = {"hello", "world"};
//具体实现
List<String> res = Arrays.stream(strArray)
.map(w -> w.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
System.out.println(res);
//TODO 案例
System.out.println("--------------------------------");
//Demo1:给定数组,返回数组平方和(直接使用映射)
//[1,2,3,4]=>[1,4,9,16]
Integer[] nums1 = {1, 2, 3, 4};
List<Integer> nums1List = Arrays.asList(nums1);
List<Integer> res1 = nums1List.stream().map(i -> i * i).collect(Collectors.toList());
System.out.println(res1);
System.out.println("--------------------------------");
//Demo2:给定两数组,返回数组对
//[1,2,3],[3,4]=>[1,3],[1,4],[2,3],[2,4],[3,3],[3,4]
Integer[] nums2 = {1, 2, 3};
Integer[] nums3 = {3, 4};
List<Integer> nums2List = Arrays.asList(nums2);
List<Integer> nums3List = Arrays.asList(nums3);
//使用2个map嵌套过滤
List<int[]> res2 = nums2List.stream().flatMap(i -> nums3List.stream().map(j -> new int[]{i, j})).collect(Collectors.toList());
System.out.println(res2.size());
System.out.println("--------------------------------");
//Demo3:针对Demo2和Demo1组合返回总和能被3整除的数对
//(2,4)和(3,3)是满足条件的
List<int[]> res3 = nums2List.stream().flatMap(i -> nums3List.stream().filter(j -> (i + j) % 3 == 0).map(j -> new int[]{i, j})).collect(Collectors.toList());
System.out.println(res3.size());
}
}
List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().map(x -> {
return x.stream().map(a -> a.toUpperCase());
}).forEach(x ->x.forEach(a->output(a)));
List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().flatMap(x -> x.stream()).map(x->x.toUpperCase()).forEach(x -> output(x));