从员工集合中筛选出salary大于8000的员工,并放置到新的集合里。
统计员工的最高薪资、平均薪资、薪资之和。
将员工按薪资从高到低排序,同样薪资者年龄小者在前。
将员工按性别分类,将员工按性别和地区分类,将员工按薪资是否高于8000分为两部分。
用传统的迭代处理也不是很难,但代码就显得冗余了,跟Stream相比高下立判。
前提:员工类
class StreamTest {
private static List<Person> personList = new ArrayList<Person>();
@BeforeEach
private void initPerson() {
personList.add(new Person("张三", 8, 3000));
personList.add(new Person("李四", 18, 5000));
personList.add(new Person("王五", 28, 7000));
personList.add(new Person("孙六", 38, 9000));
// personList.add(new Person("zhangsan", 25, 3000, "male", "tieling"));
// personList.add(new Person("lisi", 27, 5000, "male", "tieling"));
// personList.add(new Person("wangwu", 29, 7000, "female", "tieling"));
// personList.add(new Person("sunliu", 26, 3000, "female", "dalian"));
// personList.add(new Person("yinqi", 27, 5000, "male", "dalian"));
// personList.add(new Person("guba", 21, 7000, "female", "dalian"));
}
}
1. 遍历/匹配(foreach/find/match)
Stream也是支持类似集合的遍历和匹配元素的,只是 Stream中的元素是以 Optional类型存在的。Stream的遍历、匹配非常简单。
@Test
void test01() {
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
// 遍历输出符合条件的元素
list.stream().filter(x -> x > 6).forEach(System.out::println);
// 匹配第一个
Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
// 匹配任意(适用于并行流)
Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
// 是否包含符合特定条件的元素
boolean anyMatch = list.stream().anyMatch(x -> x > 6);
System.out.println("匹配第一个值:" + findFirst.get());
System.out.println("匹配任意一个值:" + findAny.get());
System.out.println("是否存在大于6的值:" + anyMatch);
System.out.println(personList);
}
2. 按条件匹配filter
(1)筛选员工中已满18周岁的人,并形成新的集合
/**
* 筛选员工中已满18周岁的人,并形成新的集合
* @思路
* List<Person> list = new ArrayList<Person>();
* for(Person person : personList) {
* if(person.getAge() >= 18) {
* list.add(person);
* }
* }
*/
@Test
void filter01() {
List<Person> collect = personList.stream().filter(x -> x.getAge()>=18).collect(Collectors.toList());
System.out.println(collect);
}
(2)自定义条件匹配
@Test
void filter02() {
List<Person> collect = personList.stream().filter(x -> x.getName().equals("zhangsan")).collect(Collectors.toList());
System.out.println(collect);
}
3. 聚合max、min、count
(1)获取String集合中最长的元素
/**
* 获取String集合中最长的元素
* @思路
* List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "sunliu");
* String max = "";
* int length = 0;
* int tempLength = 0;
* for(String str : list) {
* tempLength = str.length();
* if(tempLength > length) {
* length = str.length();
* max = str;
* }
* }
*/
@Test
void test02() {
List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "sunliu");
Comparator<? super String> comparator = Comparator.comparing(String::length);
Optional<String> max = list.stream().max(comparator);
System.out.println(max);
}
(2)获取Integer集合中的最大值
//获取Integer集合中的最大值
@Test
void test03() {
List<Integer> list = Arrays.asList(1, 17, 27, 7);
Optional<Integer> max = list.stream().max(Integer::compareTo);
// 自定义排序
Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
System.out.println(max2);
}
(3)获取员工中年龄最大的人
//获取员工中年龄最大的人
@Test
void test04() {
Comparator<? super Person> comparator = Comparator.comparingInt(Person::getAge);
Optional<Person> max = personList.stream().max(comparator);
System.out.println(max);
}
(4)计算integer集合中大于10的元素的个数
@Test
void test05() {
List<Integer> list = Arrays.asList(1, 17, 27, 7);
long count = list.stream().filter(x -> x > 10).count();
System.out.println(count);
}
4. map与flatMap
map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
(1)字符串大写
@Test
void test06() {
List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "sunliu");
list.stream().forEach(x -> x.toUpperCase());
List<String> collect1 = list.stream().map(x -> x.toUpperCase()).collect(Collectors.toList());
List<String> collect2 = list.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println(collect1);
System.out.println(collect2);
}
(2)整数数组每个元素+3
/**
* 整数数组每个元素+3
* @思路
* List<Integer> list = Arrays.asList(1, 17, 27, 7);
List<Integer> list2 = new ArrayList<Integer>();
for(Integer num : list) {
list2.add(num + 3);
}
@return [4, 20, 30, 10]
*/
@Test
void test07() {
List<Integer> list = Arrays.asList(1, 17, 27, 7);
List<Integer> collect = list.stream().map(x -> x + 3).collect(Collectors.toList());
System.out.println(collect);
}
(3)公司效益好,每人涨2000
/**
* 公司效益好,每人涨2000
*
*/
@Test
void test08() {
List<Person> collect = personList.stream().map(x -> {
x.setSalary(x.getSalary() + 2000);
return x;
}).collect(Collectors.toList());
System.out.println(collect);
}
5. 规约reduce
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
(1)求Integer集合的元素之和、乘积和最大值
/**
* 求Integer集合的元素之和、乘积和最大值
*
*/
@Test
void test10() {
List<Integer> list = Arrays.asList(1, 2, 3, 4);
//求和
Optional<Integer> reduce = list.stream().reduce((x,y) -> x+ y);
System.out.println("求和:"+reduce);
//求积
Optional<Integer> reduce2 = list.stream().reduce((x,y) -> x * y);
System.out.println("求积:"+reduce2);
//求最大值
Optional<Integer> reduce3 = list.stream().reduce((x,y) -> x>y?x:y);
System.out.println("求最大值:"+reduce3);
}
(2)求所有员工的工资之和和最高工资
/*
* 求所有员工的工资之和和最高工资
*/
@Test
void test14() {
Optional<Integer> reduce = personList.stream().map(Person :: getSalary).reduce(Integer::sum);
Optional<Integer> reduce2 = personList.stream().map(Person :: getSalary).reduce(Integer::max);
System.out.println("工资之和:"+reduce);
System.out.println("最高工资:"+reduce2);
}
6. 收集(toList、toSet、toMap)
(1)取出大于18岁的员工转为map
/**
* 取出大于18岁的员工转为map
*
*/
@Test
void test15() {
Map<String, Person> collect = personList.stream().filter(x -> x.getAge() > 18).collect(Collectors.toMap(Person::getName, y -> y));
System.out.println(collect);
}
7. collect
Collectors提供了一系列用于数据统计的静态方法:
计数: count
平均值: averagingInt、 averagingLong、 averagingDouble
最值: maxBy、 minBy
求和: summingInt、 summingLong、 summingDouble
统计以上所有: summarizingInt、 summarizingLong、 summarizingDouble
/**
* 统计员工人数、平均工资、工资总额、最高工资
*/
@Test
void test16(){
//统计员工人数
Long count = personList.stream().collect(Collectors.counting());
//求平均工资
Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
//求最高工资
Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
//求工资之和
Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
//一次性统计所有信息
DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
System.out.println("统计员工人数:"+count);
System.out.println("求平均工资:"+average);
System.out.println("求最高工资:"+max);
System.out.println("求工资之和:"+sum);
System.out.println("一次性统计所有信息:"+collect);
}
8. 分组(partitioningBy/groupingBy)
分区:将stream按条件分为两个 Map,比如员工按薪资是否高于8000分为两部分。
分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。
将员工按薪资是否高于8000分为两部分;将员工按性别和地区分组:
@Test
void test17() {
// 将员工按薪资是否高于8000分组
Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
// 将员工按性别分组
Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
// 将员工先按性别分组,再按地区分组
Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
System.out.println("员工按薪资是否大于8000分组情况:" + part);
System.out.println("员工按性别分组情况:" + group);
System.out.println("员工按性别、地区:" + group2);
}
9. 连接joining
joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。
@Test
void test18() {
String names = personList.stream().map(x -> x.getName()).collect(Collectors.joining(","));
System.out.println(names);
}
10. 排序sorted
@Test
void test19(){
// 按工资升序排序(自然排序)
List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)
.collect(Collectors.toList());
// 按工资倒序排序
List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
.map(Person::getName).collect(Collectors.toList());
// 先按工资再按年龄升序排序
List<String> newList3 = personList.stream()
.sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
.collect(Collectors.toList());
// 先按工资再按年龄自定义排序(降序)
List<String> 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("按工资升序排序:" + newList);
System.out.println("按工资降序排序:" + newList2);
System.out.println("先按工资再按年龄升序排序:" + newList3);
System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
}
11. 提取/组合
流也可以进行合并、去重、限制、跳过等操作。
@Test
void test20(){
String[] arr1 = { "a", "b", "c", "d" };
String[] arr2 = { "d", "e", "f", "g" };
Stream<String> stream1 = Stream.of(arr1);
Stream<String> stream2 = Stream.of(arr2);
// concat:合并两个流 distinct:去重
List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
// limit:限制从流中获得前n个数据
List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
// skip:跳过前n个数据
List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(3).limit(5).collect(Collectors.toList());
System.out.println("流合并:" + newList);
System.out.println("limit:" + collect);
System.out.println("skip:" + collect2);
}
12. 计算两个list中的差集
@Test
void test21(){
//计算两个list中的差集
List<String> allList = Arrays.asList( "a", "b", "c", "d");
List<String> wList = Arrays.asList( "a", "b", "e", "d");
List<String> reduce1 = allList.stream().filter(item -> !wList.contains(item)).collect(Collectors.toList());
System.out.println(reduce1);
}