Java Stream流操作

1. 获取stream流
1.1 集合Collection类型 (包含List、Set等)

java.util.Collection.stream()

List<Integer> list = new ArrayList<Integer>(){{add(1);add(2);}};
list.stream(); // 生成Stream对象(串行流)
1.2 数组类型
int[] array={1,2};
Arrays.stream(array); // 生成Stream对象(串行流)
2. 串行流、并行流
  • 串行流和并行流粗暴的理解就是处理的时候是单线程处理,还是多线程处理
  • 并行流的处理效率高于串行流,适用于对数据处理没有顺序要求的场景
list.stream(); // 串行流 (主线程按顺序对流执行操作)
list.parallelStream(); // 并行流 (以多线程并行执行的方式对流进行操作)
list.stream().parallel(); // 将串行流转换为并行流
3. 遍历(forEach / forEachOrdered)
  • forEach: 串行流是有序遍历,并行流时无序遍历。
  • forEachOrdered:有序遍历。即使并行流也是有序遍历!!!
List<Integer> list = new ArrayList<Integer>(){{add(1);add(2);add(3);add(4);add(5);add(6);}};

list.stream().forEach(i -> {
    System.out.println(i);
});

list.stream().forEachOrdered(i -> {
    System.out.println(i);
});
4. 查找(findFirst / findAny)
List<Integer> list = new ArrayList<Integer>(){{add(1);add(2);add(3);add(4);add(5);add(6);}};

// Optional如果值存在则isPresent()方法会返回true,调用get()方法会返回存储的对象。
Optional<Integer> optional = list.stream().findFirst(); // 返回流中的第一个对象
if(optional.isPresent()){
	System.out.println(optional.get());
}

Optional<Integer> optional1 = list.stream().findAny(); // 返回流中的任一对象
if(optional1.isPresent()){
	System.out.println(optional1.get());
}
5. 匹配 (anyMatch / allMatch/ noneMatch)
List<Integer> list = new ArrayList<Integer>(){{add(1);add(2);add(3);add(4);add(5);add(6);}};

Boolean flag = list.stream().anyMatch(i -> i > 3);   // true    是否存在大于3的值
Boolean flag1 = list.stream().allMatch(i -> i > 3);  // false   是否每个值都大于3
Boolean flag2 = list.stream().noneMatch(i -> i > 3); // false   是否不存在大于3的值
6. 过滤(filter)
List<Integer> list = new ArrayList<Integer>(){{add(1);add(2);add(3);add(4);add(5);add(6);}};

Stream<Integer> stream = list.stream().filter(i -> i >3); // 过滤出大于3的值
stream.forEach(System.out::print); // 打印结果:456
7. map / flatMap / peek
  • 将原始流中的元素按照传入的函数一个一个执行一遍,把每个函数return的结果组装成一个新的流。
  • 注意:元素经过处理后,原始的流的数据等于被修改!!!如果想不变就new一个新对象作为来操作~
7.1 区别
  • map
    1. 原始流中每个元素执行一遍函数,函数return的结果可以为任意类型,该结果作为一个新的元素
    2. 这些新的元素组成一个新的流
    3. 最终产生的流中元素个数和原始流中元素个数一致
    4. 也就是说将原始流中元素一个一个变成新的样貌,只是变了样子,然后再把他们收集起来
  • flatMap
    1. 原始流中每个元素执行一遍函数,函数return的结果必须是一个流类型。(元素变成了流。而不是元素改个样子,还作为元素!!!
    2. 将这些流连接在一起
    3. 最终产生的流中元素个数和原始流中元素个数是可能不一致的
    4. 原始流中的每个元素都变成了流,那么就是元素升级了
    5. 因为每个流中本身就可以有多个元素,所以最终的流中元素数量会出现比原来的流的元素数量还多的可能
7.2 演示
@Slf4j
public class StreamMainTest {

    public static void main(String[] args) throws JsonProcessingException {
        // 部门发奖金10W,奖金表已经安排好了
        List<Employee> employees = new ArrayList<Employee>(){{
            add(new Employee("Tom", 10000));
            add(new Employee("Lily", 15000));
            add(new Employee("Jack", 20000));
            add(new Employee("Kate", 25000));
            add(new Employee("Nancy", 30000));
        }};

        // 想到还有几个新来的,领导说新来的也给点福利
        // 方案1:大家先一人扣2000,然后再商量怎么给小弟
        List<Employee> employees1 = employees.stream().map(employee -> {
            return new Employee(employee.getName(), employee.getBonus() - 2000);
        }).collect(Collectors.toList());
        log.info("方案1:{}", new ObjectMapper().writeValueAsString(employees1));

        // 方案2:奖金大于2W的都是师傅,把多的部分给自己带的新人
        List<Employee> employees2 = employees.stream().flatMap(employee -> {
            List<Employee> result = new ArrayList<>();

            if (employee.getBonus() > 20000) {
                result.add(new Employee(employee.getName(), 20000)); // 大于2W的,那你拿2W吧
                result.add(new Employee(employee.getName() + "-小弟", employee.getBonus() - 20000));// 多的给小弟
            } else {
                result.add(employee);
            }

            return result.stream(); // 返回流
        }).collect(Collectors.toList());
        log.info("方案2:{}", new ObjectMapper().writeValueAsString(employees2));
    }
    
    @Data
    @AllArgsConstructor
    static class Employee{
        private String name;
        private int bonus;
    }
}

输出结果

方案1[
{"name":"Tom","bonus":8000},
{"name":"Lily","bonus":13000},
{"name":"Jack","bonus":18000},
{"name":"Kate","bonus":23000},
{"name":"Nancy","bonus":28000}]
方案2[
{"name":"Tom","bonus":10000},
{"name":"Lily","bonus":15000},
{"name":"Jack","bonus":20000},
{"name":"Kate","bonus":20000},
{"name":"Kate-小弟","bonus":5000},
{"name":"Nancy","bonus":20000},
{"name":"Nancy-小弟","bonus":10000}]
7.3 peek
  • 跟map相似的还有个peek
    • 差别就是map可以返回任意类型
    • peek是在原数据上做修改,可以理解为返回的还是当前数据类型,只是数据被修改了,类型不变
  • 一般用map就好了,可以用peek的时候,IDEA会提示你的,直接帮你把map优化为peek
8. 集合组装(toList / toSet/ toMap)
employees.stream().collect(Collectors.toList());
employees.stream().collect(Collectors.toSet());
employees.stream().collect(Collectors.toMap(employee -> employee.getName(), employee -> employee));
9. 排序(sort)
List<Employee> employees = new ArrayList<Employee>() {{
	add(new Employee("Jack", 20000));
	add(new Employee("Tom", 10000));
	add(new Employee("Nancy", 30000));
	add(new Employee("Lily", 15000));
	add(new Employee("Kate", 25000));
}};

// 正序
List<Employee> newEmployees = employees.stream().sorted(Comparator.comparing(Employee::getBonus)).collect(Collectors.toList());

// 倒序
employees.stream().sorted(Comparator.comparing(Employee::getBonus).reversed()).collect(Collectors.toList());
10. 拼接(joining)
  • 使用指定字符将特定内容拼接成一个字符串
String nameStr = employees.stream().map(Employee::getName).collect(Collectors.joining("-"));
11. 合并(collect) + 去重(distinct) + 限制(limit) + 跳过(skip)
List<Employee> employees1 = new ArrayList<Employee>() {{
    add(new Employee("Tom", 10000));
    add(new Employee("Lily", 15000));
}};

List<Employee> employees2 = new ArrayList<Employee>() {{
    add(new Employee("Tom", 10000));
    add(new Employee("Lily", 15000));
    add(new Employee("Jack", 20000));
    add(new Employee("Kate", 25000));
    add(new Employee("Nancy", 30000));
}};

// 合并
List<Employee> employees3 = Stream.concat(employees1.stream(), employees2.stream()).collect(Collectors.toList());

// 去重 (TODO 去重原理,如何判定重复???)
List<Employee> employees4 = employees3.stream().distinct().collect(Collectors.toList());

// 取前几个元素
List<Employee> employees5 = employees4.stream().limit(3).collect(Collectors.toList());

// 跳过前几个,取后续元素
List<Employee> employees6 = employees4.stream().skip(3).collect(Collectors.toList());

// skip 和 limit 结合,取中间元素
List<Employee> employees7 = employees4.stream().skip(2).limit(2).collect(Collectors.toList());
12. 分区(partitioningBy) | 分组(groupingBy)
  • 分区:使用断言方式分区(只有两个区:true, false)
  • 分组:使用函数方式分组(可以有多个组)
 public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();

        List<Employee> employees = new ArrayList<Employee>() {{
            add(new Employee("Tom", 1, 10000));
            add(new Employee("Lily", 0, 15000));
            add(new Employee("Jack", 1, 20000));
            add(new Employee("Kate", 0, 25000));
            add(new Employee("Nancy", 0, 30000));
        }};

        // 按照奖金是否大于2W分区:
        Map<Boolean, List<Employee>> part = employees.stream().collect(Collectors.partitioningBy(employee -> employee.getBonus() > 20000));
        log.info("按照奖金是否大于2W分区 {}", objectMapper.writeValueAsString(part));

        // 按照性别分组
        Map<Integer, List<Employee>> group = employees.stream().collect(Collectors.groupingBy(Employee::getSex));
        log.info("按照性别分组 {}", objectMapper.writeValueAsString(group));

        // 先分区再分组
        Map<Boolean, Map<Integer, List<Employee>>> part_group = employees.stream().collect(Collectors.partitioningBy(employee -> employee.getBonus() > 20000, Collectors.groupingBy(Employee::getSex)));
        log.info("先分区再分组 {}", objectMapper.writeValueAsString(part_group));

        // 先分组再分区
        Map<Integer, Map<Boolean, List<Employee>>> group_part = employees.stream().collect(Collectors.groupingBy(Employee::getSex, Collectors.partitioningBy(employee -> employee.getBonus() > 20000)));
        log.info("先分组再分区 {}", objectMapper.writeValueAsString(group_part));
    }

    @Data
    @AllArgsConstructor
    public static class Employee {
        private String name;
        private int sex;
        private int bonus;
    }

输出

按照奖金是否大于2W分区 
{
	"false": [{
		"name": "Tom",
		"sex": 1,
		"bonus": 10000
	}, {
		"name": "Lily",
		"sex": 0,
		"bonus": 15000
	}, {
		"name": "Jack",
		"sex": 1,
		"bonus": 20000
	}],
	"true": [{
		"name": "Kate",
		"sex": 0,
		"bonus": 25000
	}, {
		"name": "Nancy",
		"sex": 0,
		"bonus": 30000
	}]
}

按照性别分组 
{
	"0": [{
		"name": "Lily",
		"sex": 0,
		"bonus": 15000
	}, {
		"name": "Kate",
		"sex": 0,
		"bonus": 25000
	}, {
		"name": "Nancy",
		"sex": 0,
		"bonus": 30000
	}],
	"1": [{
		"name": "Tom",
		"sex": 1,
		"bonus": 10000
	}, {
		"name": "Jack",
		"sex": 1,
		"bonus": 20000
	}]
}

先分区再分组 
{
	"false": {
		"0": [{
			"name": "Lily",
			"sex": 0,
			"bonus": 15000
		}],
		"1": [{
			"name": "Tom",
			"sex": 1,
			"bonus": 10000
		}, {
			"name": "Jack",
			"sex": 1,
			"bonus": 20000
		}]
	},
	"true": {
		"0": [{
			"name": "Kate",
			"sex": 0,
			"bonus": 25000
		}, {
			"name": "Nancy",
			"sex": 0,
			"bonus": 30000
		}]
	}
}

先分组再分区 
{
	"0": {
		"false": [{
			"name": "Lily",
			"sex": 0,
			"bonus": 15000
		}],
		"true": [{
			"name": "Kate",
			"sex": 0,
			"bonus": 25000
		}, {
			"name": "Nancy",
			"sex": 0,
			"bonus": 30000
		}]
	},
	"1": {
		"false": [{
			"name": "Tom",
			"sex": 1,
			"bonus": 10000
		}, {
			"name": "Jack",
			"sex": 1,
			"bonus": 20000
		}],
		"true": []
	}
}
13. 统计运算
13.1 统计A:
  • max:最大
  • min:最小
  • count:数量
// 奖金最高的出来
Optional<Employee> optional = employees.stream().max(Comparator.comparing(Employee::getBonus));
if(optional.isPresent()){
    System.out.println(optional.get().getName());
}

// 奖金最低的出来
Optional<Employee> optional1 = employees.stream().min(Comparator.comparing(Employee::getBonus));
if(optional1.isPresent()){
    System.out.println(optional1.get().getName());
}

// 女的有几个人啊
long count = employees.stream().filter(employee -> employee.getSex() == 0).count();
System.out.println(count);
13.2 统计B:
  • maxBy:最大
  • minBy:最小
  • averagingInt:平均
  • summingInt:总和
  • counting:数量
  • summarizingInt:以上全部
List<Employee> employees = new ArrayList<Employee>() {{
    add(new Employee("Tom", 1, 10000));
    add(new Employee("Lily", 0, 15000));
    add(new Employee("Jack", 1, 20000));
    add(new Employee("Kate", 0, 25000));
    add(new Employee("Nancy", 0, 30000));
}};

Optional<Integer> max = employees.stream().map(Employee::getBonus).collect(Collectors.maxBy(Integer::compareTo));
System.out.println("最大奖金:" + max);

Optional<Integer> min = employees.stream().map(Employee::getBonus).collect(Collectors.minBy(Integer::compareTo));
System.out.println("最低奖金:" + min);

Double averag =  employees.stream().collect(Collectors.averagingInt(Employee::getBonus));
System.out.println("平均奖金:" + averag);

Integer sum = employees.stream().collect(Collectors.summingInt(Employee::getBonus));
System.out.println("奖金总额:" + sum);

Long count = employees.stream().collect(Collectors.counting());
System.out.println("奖金份数:" + count);

IntSummaryStatistics summarizing =  employees.stream().collect(Collectors.summarizingInt(Employee::getBonus));
System.out.println("最大奖金:" + summarizing.getMax());
System.out.println("最低奖金:" + summarizing.getMin());
System.out.println("平均奖金:" + summarizing.getAverage());
System.out.println("奖金总额:" + summarizing.getSum());
System.out.println("奖金份数:" + summarizing.getCount());
13.3 运算 reduce(归约)
List<Double> list = new ArrayList<Double>(){{add(1d);add(2d);add(3d);add(4d);add(5d);add(6d);}};

Optional<Double> max = list.stream().reduce((x, y) -> x > y ? x : y);
System.out.println("大: " + max);

Optional<Double> min = list.stream().reduce((x, y) -> x < y ? x : y);
System.out.println("小: " + min);

Optional<Double> sum = list.stream().reduce((x, y) -> x + y);
System.out.println("加: " + sum);

Double subtract = list.stream().reduce(10000d, (x, y) -> x - y);
System.out.println("减: " + subtract);

Optional<Double> product = list.stream().reduce((x, y) -> x * y);
System.out.println("乘: " + product);

Double divide = list.stream().reduce(10000d, (x, y) -> x / y);
System.out.println("除: " + divide);

输出

: Optional[6.0]: Optional[1.0]: Optional[21.0]: 9979.0: Optional[720.0]: 13.888888888888891
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值