Stream流——Java8新特性之一
用于处理集合,它可以指定你希望对集合进行的 *** 作,可以执行非常复杂的查找、过滤和映射数据等 *** 作。
本文只给出方法以及其用法,可作为工具书来使用。
对Stream的理解、研究与总结可参考这篇文章:——(待整理)——
进入正题。
使用到的实体类:
@Data @AllArgsConstructor @NoArgsConstructor class Student { private String name; private int age; }
@Data、@AllArgsConstructor、@NoArgsConstructor三个注解是在maven里面引用了lombok,作用是帮我们创建了get、set、有参与无参构造方法,也可以自己手动创建。
流的创建:
// 1、通过 Collection.stream() 方法用集合创建流 Listlist = Arrays.asList("a", "b", "c"); // 创建一个顺序流 Stream stream = list.stream(); // 创建一个并行流 Stream parallelStream = list.parallelStream(); Stream parallelStream2 = list.stream().parallel(); // 2、使用 Arrays.stream(T[] array) 方法用数组创建流 int[] array={1,3,5,6,8}; IntStream intStream = Arrays.stream(array); // 3、使用Stream的静态方法:of()、iterate()、generate() Stream stream1 = Stream.of(1, 2, 3, 4, 5, 6); stream1.forEach(System.out::println); Stream stream2 = Stream.iterate(0, (x) -> x + 3).limit(10); stream2.forEach(System.out::println); Stream stream3 = Stream.generate(Math::random).limit(3); stream3.forEach(System.out::println);
filter:筛选
Listlist = Arrays.asList(6, 7, 3, 8, 1, 2, 9); Stream stream = list.stream(); stream.filter(x -> x > 7).forEach(System.out::println);
concat:合并
String[] arr1 = {"a", "b", "c", "d"}; String[] arr2 = {"d", "e", "f", "g"}; Streamstream1 = Stream.of(arr1); Stream stream2 = Stream.of(arr2); List newList = Stream.concat(stream1, stream2).collect(Collectors.toList()); System.out.println("流合并:" + newList);// 流合并:[a, b, c, d, d, e, f, g]
distinct:去重
Integer[] arr = {1, 2, 2, 3, 4, 4, 5}; Listlist = Arrays.stream(arr).distinct().collect(Collectors.toList()); System.out.println("流去重:" + list);// 流去重:[1, 2, 3, 4, 5]
skip:跳过前n个数据
Listcollect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList()); System.out.println("skip:" + collect2);// skip:[3, 5, 7, 9, 11]
limit:获取前n个元素
Listcollect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList()); System.out.println("limit:" + collect);// limit:[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
skip和limit加起来可以实现分页功能。
map:映射,函数会被应用到每个元素上,并将其映射成一个新的元素。
String[] strArr = {"rety", "fghfg", "terd", "nye"}; ListstrList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList()); System.out.println("每个元素大写:" + strList);// 每个元素大写:[RETY, FGHFG, TERD, NYE] //将每个元素转成一个新的且不带逗号的元素 List list = Arrays.asList("h,y,g,g,e", "3,6,9,12"); List listNew = list.stream().map(s -> s.replaceAll(",", "")).collect(Collectors.toList()); System.out.println("去掉逗号:" + listNew);// 去掉逗号:[hygge, 36912] List intList = Arrays.asList(2, 4, 5, 8, 10); List intListNew = intList.stream().map(x -> x + 2).collect(Collectors.toList()); System.out.println("每个元素+3:" + intListNew);// 每个元素+3:[4, 6, 7, 10, 12]
flatMap:映射,流中的每个值都换成另一个流,然后把所有流连接成一个流。
Listlist = Arrays.asList("h,y,g,g,e", "3,6,9,12"); List listNew = list.stream().flatMap(s -> { //将每个元素转换成一个stream String[] split = s.split(","); Stream s2 = Arrays.stream(split); return s2; }).collect(Collectors.toList()); System.out.println("处理前:元素个数为 " + list.size() + " 个,集合为 " + list); System.out.println("处理后:元素个数为 " + listNew.size() + " 个,集合为 " + listNew);
这里注意虽然他们的集合打印出来很相似,但是注意他们的元素个数是不一样的。
sorted:排序
// 默认排序:即无参时 Listlist = Arrays.asList(5, 6, 4); list.stream().sorted().forEach(System.out::println); // 自定义排序 List studentList = new ArrayList<>(); studentList.add(new Student("A", 10)); studentList.add(new Student("B", 20)); studentList.add(new Student("A", 30)); studentList.add(new Student("D", 40)); // 按年龄升序 studentList.stream().sorted(Comparator.comparingInt(Student::getAge)).forEach(System.out::println); // 先按姓名升序,姓名相同则按年龄升序 studentList.stream().sorted( (o1, o2) -> { if (o1.getName().equals(o2.getName())) { return o1.getAge() - o2.getAge(); } else { return o1.getName().compareTo(o2.getName()); } } ).forEach(System.out::println); // 先按姓名升序,姓名相同则按年龄升序,更简单的写法 studentList.stream().sorted(Comparator.comparing(Student::getName).thenComparing(Student::getAge)).forEach(System.out::println);
peek:消费
ListstudentList = new ArrayList<>(); studentList.add(new Student("A", 10)); studentList.add(new Student("B", 20)); System.out.println("原始数据:" + studentList); // 使用map对比 List result = studentList.stream().map(o -> { o.setAge(50); return o; }).collect(Collectors.toList()); System.out.println("使用map修改数据:" + result); // 使用peek List result1 = studentList.stream().peek(o -> o.setAge(100)).collect(Collectors.toList()); System.out.println("使用peek修改数据:" + result1);
这里专门使用了map与peek做了个对比,你会发现他们都改变了age的值,而peek区别与map,它不需要返回值。但是map能改变数据类型,peek就做不到。
所以peek 可以做一些打印或者修改工作。
源码注释中作者给的例子也证明了这种想法:
Stream.of("one", "two", "three", "four") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList());
对于map与peek的具体分析看这篇文章:——(待整理)——
max:返回流中元素的最大值
Listlist = Arrays.asList("admn", "bgfmt", "pbtd", "xbafdd", "weoufgsd"); Optional max = list.stream().max(Comparator.comparing(String::length)); System.out.println("最长的字符串:" + max.get());// 最长的字符串:weoufgsd List intlist = Arrays.asList(7, 6, 9, 4, 11, 6); Optional max2 = intlist.stream().max(Integer::compareTo); System.out.println("自然排序的最大值:" + max2.get());// 自然排序的最大值:11
min:返回流中元素的最小值
Listlist = Arrays.asList("admn", "bgfmt", "pbtd", "xbafdd", "weoufgsd"); Optional min = list.stream().min(Comparator.comparing(String::length)); System.out.println("最短的字符串:" + min.get());// 最短的字符串:admn List intList = Arrays.asList(7, 6, 9, 4, 11, 6); Optional min2 = intList.stream().min(Integer::compareTo); System.out.println("自然排序的最小值:" + min2.get());// 自然排序的最小值:4
count:返回流中元素的总个数
Listlist = Arrays.asList(7, 6, 4, 8, 2, 11, 9); long count = list.stream().count(); System.out.println("list的元素总个数:" + count);// list的元素总个数:7 long countOfGt6 = list.stream().filter(x -> x > 6).count(); System.out.println("list中大于6的元素个数:" + countOfGt6);// list中大于6的元素个数:4
allMatch:接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false
Listlist = Arrays.asList(7, 6, 9, 3, 8, 2, 1); boolean allMatch = list.stream().allMatch(x -> x > 6); System.out.println("是否全部值都大于6:" + allMatch);// 是否全部值都大于6:false
noneMatch:接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
Listlist = Arrays.asList(7, 6, 9, 3, 8, 2, 1); boolean noneMatch = list.stream().noneMatch(x -> x > 6); System.out.println("是否不存在大于6的值:" + noneMatch);// 是否不存在大于6的值:false
anyMatch:接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
Listlist = Arrays.asList(7, 6, 9, 3, 8, 2, 1); boolean anyMatch = list.stream().anyMatch(x -> x > 6); System.out.println("是否存在大于6的值:" + anyMatch);// 是否存在大于6的值:true
findFirst:返回流中第一个元素
Listlist = Arrays.asList(7, 6, 9, 3, 8, 2, 1); Optional findFirst = list.stream().findFirst(); System.out.println("list中的第一个数:"+findFirst.get());// list中的第一个数:7 Optional findFirstGt7 = list.stream().filter(x -> x > 7).findFirst(); System.out.println("list中第一个大于7的数:"+findFirstGt7.get());// list中第一个大于7的数:9
findAny:返回流中的任意元素
// 适用于并行流,源码有注释:This is to allow for maximal performance in parallel operations Listlist = Arrays.asList(7, 6, 9, 3, 8, 2, 1); Optional findAny = list.parallelStream().findAny(); System.out.println("匹配任意一个值:" + findAny.get());// 匹配任意一个值:8 Optional findAnyGt5 = list.parallelStream().filter(x -> x > 5).findAny(); System.out.println("匹配任意一个大于5的值:" + findAnyGt5.get());// 匹配任意一个大于5的值:8
PS:使用上面代码自己测试的时候,得多次运行才可能得到不一样的返回值,可以试着改变list的长度或者类型来增加返回不同值的概率。
reduce:归约
例子中也可以使用(x, y) -> x > y ? x : y 替换 Integer::max
Listlist = Arrays.asList(1, 3, 2, 8, 11, 4); // 一个参数:Optional reduce(BinaryOperator accumulator) Optional sum = list.stream().reduce(Integer::sum); Optional product = list.stream().reduce((x, y) -> x * y); Optional max = list.stream().reduce(Integer::max); System.out.println("list求和:" + sum.get()+ ",求积:" + product.get()+",最大值:" + max.get());// list求和:29,求积:2112,最大值:11 // 两个参数:T reduce(T identity, BinaryOperator accumulator) Integer sum2 = list.stream().reduce(0, Integer::sum); Integer product2 = list.stream().reduce(1, (x, y) -> x * y); Integer max2 = list.stream().reduce(0, Integer::max); System.out.println("list求和:" + sum2+ ",求积:" + product2+",最大值:" + max2);// list求和:29,求积:2112,最大值:11 // U reduce(U identity,BiFunction accumulator,BinaryOperator combiner) Integer sum3 = list.parallelStream().reduce(0, Integer::sum, Integer::sum); Integer product3 = list.stream().reduce(1, (x, y) -> x * y, (x, y) -> x * y); Integer max3 = list.stream().reduce(0, Integer::max, Integer::max); System.out.println("list求和:" + sum3+ ",求积:" + product3+",最大值:" + max3);// list求和:29,求积:2112,最大值:11
reduce三种不同方式的分析,请看这篇文章:——(待整理)——
collect:归集 (Collectors:toList/toSet/toMap)
Liststudents = new ArrayList<>(); students.add(new Student("A", 10)); students.add(new Student("B", 20)); students.add(new Student("C", 10)); // 转成list:toList List ageList = students.stream().map(Student::getAge).collect(Collectors.toList()); System.out.println("ageList:" + ageList);// ageList:[10, 20, 10] // 转成Set:toSet Set ageSet = students.stream().map(Student::getAge).collect(Collectors.toSet()); System.out.println("ageSet:" + ageSet);// ageSet:[20, 10] // 类似Set:distinct去重 List ageSet1 = students.stream().map(Student::getAge).distinct().collect(Collectors.toList()); System.out.println("ageSet1:" + ageSet1);// ageSet1:[10, 20] // 转成Map:toMap Map studentMap = students.stream().collect(Collectors.toMap(Student::getName, Student::getAge)); System.out.println("studentMap:" + studentMap);// studentMap:{A=10, B=20, C=10}
使用collect(Collectors.toSet())与distinct().collect(Collectors.toList()),最终都能得到一个包含不重复元素的集合,但是你会发现他们元素的顺序不一样,可以大胆的猜测他们写入的顺序不一样,具体分析请看文章:——(待整理)——
上面基本上列举出了常用的方法,面对实际问题,我们使用Stream时,可以采用非常多的方式来达到目的。下面我们用一个例子以及一些问题,尽可能的给出多种解决方案,来让大家来熟悉这些方法。
用到的实体类:
@Data @AllArgsConstructor @NoArgsConstructor class Person { private String name; // 姓名 private int salary; // 薪资 private int age; // 年龄 private String sex; // 性别 private String area; // 地区 }
实例化:
ListpersonList = new ArrayList (); personList.add(new Person("张三", 39000, 23, "男", "北京")); personList.add(new Person("王五", 20000, 25, "男", "上海")); personList.add(new Person("李四", 28000, 21, "女", "上海")); personList.add(new Person("小明", 32000, 24, "女", "北京")); personList.add(new Person("小刚", 45000, 25, "男", "北京")); personList.add(new Person("小红", 29000, 26, "女", "上海"));
1、工资大于28000的人员列表
Mapmap = personList.stream().filter(p -> p.getSalary() > 28000).collect(Collectors.toMap(Person::getName, Person::getSalary)); System.out.println("高于28000的员工姓名:" + map.keySet()); List List = personList.stream().filter(x -> x.getSalary() > 28000).map(Person::getName).collect(Collectors.toList()); System.out.println("高于28000的员工姓名:" + List);
2、改变员工信息
// 不改变原来员工集合的方式 ListpersonListNew = personList.stream().map(person -> { Person personNew = new Person(person.getName(), 0, 0, null, null); personNew.setSalary(person.getSalary() + 10000); return personNew; }).collect(Collectors.toList()); System.out.println("一次改动前:" + personList); System.out.println("一次改动后:" + personListNew); // 改变原来员工集合的方式 List personListNew2 = personList.stream().map(person -> { person.setSalary(person.getSalary() + 10000); return person; }).collect(Collectors.toList()); System.out.println("二次改动前:" + personList); System.out.println("二次改动后:" + personListNew2);
3、求工资之和方式:
OptionalsumSalary = personList.stream().map(Person::getSalary).reduce(Integer::sum); Integer sumSalary2 = personList.stream().map(Person::getSalary).reduce(0, Integer::sum); Integer sumSalary3 = personList.parallelStream().reduce(0, (sum, p) -> sum += p.getSalary(), Integer::sum); OptionalInt sumSalary4 = personList.stream().mapToInt(Person::getSalary).reduce(Integer::sum); int sumSalary5 = personList.stream().mapToInt(Person::getSalary).sum(); Integer sumSalary6 = personList.stream().collect(Collectors.summingInt(Person::getSalary)); System.out.println("工资之和:" + sumSalary.get() + "," + sumSalary2 + "," + sumSalary3 + "," + sumSalary4.getAsInt() + "," + sumSalary5 + "," + sumSalary6);
4、求最高工资方式:
OptionalmaxSalary = personList.stream().map(Person::getSalary).reduce((max1, max2) -> max1 > max2 ? max1 : max2); Optional maxSalary2 = personList.stream().map(Person::getSalary).reduce(Integer::max); Integer maxSalary3 = personList.stream().map(Person::getSalary).reduce(0, Integer::max); Integer maxSalary4 = personList.parallelStream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(), Integer::max); Optional maxSalary5 = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare)); Optional maxSalary6 = personList.stream().map(Person::getSalary).max(Integer::compare); Optional maxSalary7 = personList.stream().max(Comparator.comparingInt(Person::getSalary)); System.out.println("最高工资:" + maxSalary.get() + "," + maxSalary2.get() + "," + maxSalary3 + "," + maxSalary4 + "," + maxSalary5.get() + "," + maxSalary6.get() + "," + maxSalary7.get().getSalary());
5、求平均工资
Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary)); Double average2 = personList.stream().mapToDouble(Person::getSalary).sum() / personList.size(); System.out.println("员工平均工资:" + average + "," + average2);
6、求人员总数
long count = personList.stream().collect(Collectors.counting()); long count2 = personList.stream().count(); long count3 = personList.size(); System.out.println("员工总数:" + count + "," + count2 + "," + count3);
7、一次性统计所有信息
DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary)); System.out.println("员工工资所有统计:" + collect);
8、分组
// 将员工按薪资是否高于8000分组 Map> groupBySalary = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000)); System.out.println("按员工薪资是否大于8000分组情况:" + groupBySalary); // 将员工按性别分组 Map > groupBySex = personList.stream().collect(Collectors.groupingBy(Person::getSex)); System.out.println("按员工性别分组情况:" + groupBySex); // 将员工先按性别分组,再按地区分组 Map >> group = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea))); System.out.println("按员工性别、地区:" + group);
9、排序
// 按工资升序排序(自然排序) ListnewList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName) .collect(Collectors.toList()); System.out.println("按工资升序排序:" + newList); // 按工资倒序排序 List newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()) .map(Person::getName).collect(Collectors.toList()); System.out.println("按工资降序排序:" + newList2); // 先按工资再按年龄升序排序 List newList3 = personList.stream() .sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName) .collect(Collectors.toList()); System.out.println("先按工资再按年龄升序排序:" + newList3); // 先按工资再按年龄自定义排序(降序) List newList4 = personList.stream().sorted((p1, p2) -> { if (p1.getSalary() == p2.getSalary()) { return p2.getAge() - p1.getAge(); } else { return p2.getSalary() - p1.getSalary(); } }).map(Person::getName).collect(Collectors.toList()); System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
上面有些方法其实使用并不恰当,在这里只是起到了抛砖引玉的作用,大家选取最适用的的即可。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)