用传统for循环处理复杂计算代码虽然也不是很难,但代码就显得冗余了。跟Stream相比就显而易见。配合出现的Lambda表达式,给我们操作集合类提供了方便。
定义
Stream将要处理的元素集合看作一种流,在流的过程。借助Stream对流中的元素进行操作,比如筛选、排序、集合等‘
Stream可以由数组或集合创建。对流的操作分为两种:
另外,Stream有几个新的特性:
stream()
List<String> list=new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Stream<String> stream = list.stream();//创建一个顺序流
System.out.println(stream);
//创建一个并行流
Stream<String> stringStream = list.parallelStream();
System.out.println(stringStream);
Arrays.stream();
int [] array={1,3,5,7,9};
IntStream stream1 = Arrays.stream(array);
System.out.println(stream1);
of(); 、 iterator();、generate();
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
System.out.println(integerStream);
System.out.println("=================");
Stream<Integer> limit = Stream.iterate(1, (x) -> x + 2).limit(5);//打印从1 每次加2,数量为5
limit.forEach(System.out::println);
System.out.println("=================");
Stream<Double> limit1 = Stream.generate(Math::random).limit(3);//随机生成个3个小数
limit1.forEach(System.out::println);
如果流中的数据量足够大,并行流可以加快速度,除了直接创建并行流。还可以通过parallel()把顺序流转换成并行流:
在使用stream之前,先理解Optional的概念
Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法返回true,调用get()方法返回该对象。
详解见 :菜鸟教程Java 8 Optional类
List list=new ArrayList<>();
list.add(8);
list.add(9);
list.add(1);
list.add(3);
//筛选大于6 的第一个数字
Optional<Integer> s= list.stream().parallel().filter(x->x>6).findFirst();
List<Integer> list= Arrays.asList(1,2,3,4,5,6,7,8,9);
//筛选所有大于7的数字
list.stream().filter(x->x>7).forEach(System.out::println);
System.out.println("========");
//匹配第一个大于1的数字
Optional<Integer> first = list.stream().filter(x->x>1).findFirst();
System.out.println(first.get());
System.out.println("========");
//匹配任意一个大于1的数字
Optional<Integer> any = list.parallelStream().filter(x -> x > 1).findAny();
System.out.println(any.get());
System.out.println("========");
boolean b = list.stream().anyMatch(x -> x > 7);
System.out.println(b);
筛选是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中。
将用多个案例帮助理解使用Stream
Person类:
@Data
@AllArgsConstructor
public class Person {
private String name;
private Integer age;
private String sex;
private Double salary;
private String area;
}
List<Person> personList=new ArrayList<>();
personList.add(new Person("张三",20,"男",8900.00,"江苏盐城"));
personList.add(new Person("李四",21,"男",7000.00,"江苏镇江"));
personList.add(new Person("王五",22,"男",7800.00,"江苏常州"));
personList.add(new Person("张丽",23,"女",8200.00,"江苏淮安"));
personList.add(new Person("王茜",24,"女",9500.00,"江苏南通"));
personList.add(new Person("陈涵",22,"女",7900.00,"江苏南京"));
筛选员工中工资高于8000的人,形成新的集合。形成的集合使用collect()收集。
List<Person> collect =personList.stream.filter(person-> person.getSalary()>8000).collect(Collector.toList);
System.out.println(collect);
案例1:获取String 中最长的元素值
List<String> ListA=Arrays.asList("Admin","Test","Manager","Develop");
Optional<String>max=ListA.stream.max(Compatrator.comparing(String::length));
System.out.println(max.get());
List<Integer> integerList=Arrays.asList(1,3,5,7,2,4);
Optional<Integer> max=integerList.stream.max(Integer::compareTo);
System.out.println(max.get());
Optional<Person> max=personList.stream.max(Comparator.comparing(person->person.getSalary()));
System.out.println(max.get());
//第二种方法
Optional<Person> max1=personList.stream.max(Comparator.comparingDouble(Person::getSalary)));
System.out.println(max1.get());
List<Integer> integerList=Arrays.asList(1,2,3,4,5,6,7,8,9);
Long count=integerList.stream.filter(i->i>6).count();
System.out.println(count);
map/flatmap
可以将一个流的元素按照一定的规则映射到另一个流的元素上,分为map和flatmap
String[] arr={"cdc","cwerec","ggfb"};
List<String> collect=Arrays.asList(arr).stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println(collect);
List<Integer> integerList=Arrays.asList(1,5,7);
List<Integer>collect1=integer.stream.map(i->i+3).collect(Collector.toList));
System.out.println(collect1);
List<Person> newList=personList.stream.map(person->{
person.setSalary(person.getSalary+1000.00);
return person;
}).collect(Collector.toList);
System.out.println(newList);
List<String> list= Arrays.asList("m,k,l,a","1,3,5,7");
List<String> list_new1 = list.stream().flatMap(words -> {
String[] split = words.split(",");
Stream<String> list_new = Arrays.stream(split);
return list_new;
}).collect(Collectors.toList());
System.out.println("原始list"+list);
System.out.println("新的"+list_new1);
归约也就是缩减,将一个流缩减成一个值,能实现对集合的求值、求乘机和求和、求最值的操作
案例一:求Integer集合的元素之和、乘机和最大值
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
Optional<Integer> sum = integers.stream().reduce(Integer::sum);
Optional<Integer> multi = integers.stream().reduce((x, y) ->x*y);
//方式1
Integer max = integers.stream().reduce(1, Integer::max);
//方式2
Optional<Integer> max1 = integers.stream().max(Comparator.comparing(Integer::intValue));
//方式3
Optional<Integer> max2 = integers.stream().max(Integer::compareTo);
System.out.println("和"+sum.get());
System.out.println("乘"+multi);
System.out.println("最大值"+max2);
List<Person> personList=new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
personList.add(new Person("Anni", 8200, 24, "female", "New York"));
personList.add(new Person("Owen", 9500, 25, "male", "New York"));
personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
Optional<Integer> sum = personList.stream().map(Person::getSalary).reduce(Integer::sum);
Optional<Person> max = personList.stream().max(Comparator.comparing(Person::getSalary));
System.out.println("总和"+sum);
System.out.println("最大值"+max.get().getSalary());
collect,收集,把流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。
3.6.1
归集(toList/toSet/toMap)
因为流不存储数据,那么流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂的一些用法。
案例一:
List<Integer> list=Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
List<Integer> new_list = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
Set<Integer> new_Set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
Map<String, Person> new_Map = personList.stream().filter(person ->
person.getSalary() > 8000
).collect(Collectors.toMap(Person::getName, person -> person));
System.out.println("list"+new_list);
System.out.println("set"+new_Set);
System.out.println("map"+new_Map);
结果:
3.6.2统计(count/averaging)
Collectors提供了一系列用于数据统计的静态方法:
案例:统计员工人数、平均工资、工资总额、最高工资等
Long count = personList.stream().collect(Collectors.counting());
Double salary = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compareTo));
IntSummaryStatistics sum = personList.stream().collect(Collectors.summarizingInt(Person::getSalary));
DoubleSummaryStatistics sumAll = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
System.out.println("数量"+count);
System.out.println("平均工资"+salary);
System.out.println("最高工资"+max);
System.out.println("工资之和"+sum);
System.out.println("一次性信息"+sumAll);
Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
Map<String, List<Person>> part1 = personList.stream().collect(Collectors.groupingBy(Person::getSex));
Map<String, Map<String, List<Person>>> part3 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getSex)));
System.out.println("员工按薪资是否大于8000分组情况"+part);
System.out.println("员工按性别分组情况"+part1);
System.out.println("员工按性别、地区分组情况"+part3);
joining可以将stream中的元素用特定的连接符连接成一个字符串。
String joinName = personList.stream().map(person -> person.getName()).collect(Collectors.joining("-"));
List<String> list = Arrays.asList("A", "B", "C");
String collect = list.stream().collect(Collectors.joining("+"));
System.out.println("所有员工的姓名"+joinName);
System.out.println("拼接后的字符串"+collect);
Collectors类提供的reducing方法,相比于stream本身的reduce方法,增加了对于自定义归约的支持。
Optional<Integer> sumSalary = personList.stream().map(Person::getSalary).reduce(Integer::sum);
Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
System.out.println("员工薪资总和"+sumSalary.get());
System.out.println("员工薪资总和"+sum);
案例:将员工按工资由高到低(工资一样则年龄由大到小)排序
//自然排序
List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary))
.map(Person::getName).collect(Collectors.toList());
//倒序排序
List<String> newList1 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
.map(Person::getName).collect(Collectors.toList());
//先按工资再按年龄升序排序
List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary)
.thenComparing(Person::getAge)).map(Person::getName)
.collect(Collectors.toList());
System.out.println("升序排序"+newList);
System.out.println("降序排序"+newList1);
System.out.println("先按工资再按年龄升序排序"+newList2);
String[] arr1={"a","b","c","d"};
String[] arr2={"d","e","f","g"};
//去重
List<String> distinct = Stream.concat(Stream.of(arr1), Stream.of(arr2)).
distinct().collect(Collectors.toList());
//限制从流中获取n个数字
List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
List<Integer> collect1 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
System.out.println("流合并"+distinct);
System.out.println("limit"+collect);
System.out.println("skip"+collect1);