jdk8新特性(Stream流)-第一阶段-第二十三天

Stream流

1. Stream流概述

概念:java8的另一个非常优秀的新特性,可以用来非常方便的对指定的集合进行各种比如 过滤 映射 排序等等复杂的操作
StreamAPI提供了对容器中数据进行高效且方便的处理方式和IO流不同,Stream流关注的是对集合中数据的一些列操作,类似于生产线,流本身并不存储数据,也不会对数据源进行改变,操作后他们会返回一个持有处理结果的一个新的stream
集合关注的是数据的存储,流关注的是数据的运算处理

  1. Stream关注的是对数据的运算,与CPU打交道
    集合关注的是数据的存储,与内存打交道
  2. ①Stream 自己不会存储元素。
    ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
    ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
  3. Stream 执行流程
    ① Stream的实例化
    ② 一系列的中间操作(过滤、映射、…)
    ③ 终止操作
  4. 一个中间操作链,对数据源的数据进行处理
    一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

2. Stream流处理的基本步骤

Stream操作的三个步骤: 创建和获取一个流对象---->通过流对象基于数据源进行一些列的中间处理操作(形成一个处理链)—>终止操作(执行所有的中间操作并产生最终的处理结果)

Stream流的创建方式

方式一:通过集合创建Stream流
方式二:通过数组的来创建Stream流
方式三:通过Stream流的静态方法of
方式四:通过.iterate()和.generate()获取无线流

代码举例

package com.qianfeng.Test03;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamTest01 {
	public static void main(String[] args) {
		//方式一:通过集合创建Stream流
		List<String> list1 = new ArrayList<>();
		list1.add("abc");
		list1.add("def");
		list1.add("ghi");
		//集合的第一种方式.stream()方法获取Stream流
		Stream<String> stream1 = list1.stream(); 
		stream1.forEach(System.out::print);
		System.out.println("\n*************");
		//集合的第二种方式.parallelStream();(此种方式是通过多线程的方式)将一个大任务不断的拆分为很多的小任务,并压给不同的线程同时执行,最后将每个子任务的结果进行合并
		Stream<String> stream2 = list1.parallelStream();
		stream2.forEach(System.out::print);
		System.out.println("\n**************");
		
		//方式二:通过数组的来创建Stream流
		int[] arr = new int[] {1,3,5,7,9};
		IntStream stream3 = Arrays.stream(arr);
		stream3.forEach(System.out::print);
		System.out.println("\n**************");
		
		//方式三:通过Stream流的静态方法of
		Stream<Integer> stream4 = Stream.of(1,2,3,4,5);
		stream4.forEach(System.out::print);

		//方式四:通过.iterate()和.generate()获取无线流
		//遍历前10个偶数
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);

        Stream.generate(Math::random).limit(10).forEach(System.out::println);
	}
}

Stream流的中间操作

筛选与切片常见操作

filter():接受Lambda,从流中排出某些元素
distinct():去除重复元素(通过hashCode与equals)
limit():获取前指定个数元素
skip():跳过指定个数的元素
sorted():按照自然排序
sorted(Compartor c):定制排序
map():接受一个函数做为参数,并将该函数应用到每个集合的每个元素上将其映射为一个新元素,一般用来直接提取信息或转换为其他形式的信息

收集的常见操作

collect(Collector c):将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

代码举例

Employee类

package com.qianfeng.day22;

public class Employee {

	//员工编号
	private String empId;
	//员工姓名
	private String empName;
	//员工性别
	private String empGender;
	//员工年龄
	private int empAge;
	//员工工资
	private double empSalary;
	//员工状态
	private String empStatus;
	
	public Employee() {
		super();
	}

	public Employee(String empId, String empName, String empGender, int empAge, double empSalary, String empStatus) {
		super();
		this.empId = empId;
		this.empName = empName;
		this.empGender = empGender;
		this.empAge = empAge;
		this.empSalary = empSalary;
		this.empStatus = empStatus;
	}

	@Override
	public String toString() {
		return "Employee [empId=" + empId + ", empName=" + empName + ", empGender=" + empGender + ", empAge=" + empAge
				+ ", empSalary=" + empSalary + ", empStatus=" + empStatus + "]";
	}

	public String getEmpId() {
		return empId;
	}

	public void setEmpId(String empId) {
		this.empId = empId;
	}

	public String getEmpName() {
		return empName;
	}

	public void setEmpName(String empName) {
		this.empName = empName;
	}

	public String getEmpGender() {
		return empGender;
	}

	public void setEmpGender(String empGender) {
		this.empGender = empGender;
	}

	public int getEmpAge() {
		return empAge;
	}

	public void setEmpAge(int empAge) {
		this.empAge = empAge;
	}

	public double getEmpSalary() {
		return empSalary;
	}

	public void setEmpSalary(double empSalary) {
		this.empSalary = empSalary;
	}

	public String getEmpStatus() {
		return empStatus;
	}

	public void setEmpStatus(String empStatus) {
		this.empStatus = empStatus;
	}
	
}

StreamWork测试类

package com.qianfeng.day22;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class StreamWork {
	
	public static void main(String[] args) {
		List<Employee> list = new ArrayList<>();
		
		list.add(new Employee("1001","张三","男",20,8888.8,"繁忙"));
		list.add(new Employee("1002","李四","女",28,6000.128,"休闲"));
		list.add(new Employee("1003","王五","男",18,7008.8,"离职"));
		list.add(new Employee("1004","唐昊","男",22,10888.8,"繁忙"));
		list.add(new Employee("1005","赵六","女",25,6688.8,"繁忙"));
		list.add(new Employee("1006","田七","男",23,5888.8,"休闲"));
		list.add(new Employee("1007","孙八","女",18,9888.8,"繁忙"));
		
		//1.查找并输出所有工资在6000元以上的男员工
		System.out.println("1.查找并输出所有工资在6000元以上的男员工:");
		list.stream().filter(e->e.getEmpSalary()>=6000).filter(s->s.getEmpGender().equals("男")).forEach(System.out::println);
		
		//2.显示年龄最小的员工信息
		System.out.println("\n2.显示年龄最小的员工信息:");
		list.stream().sorted((e1,e2)->-e1.getEmpAge()-e2.getEmpAge()).limit(1).forEach(System.out::println);
		
		//3.显示最高的工资
		System.out.println("\n3.显示最高的工资");
		list.stream().sorted((e1,e2)->-(int)((e1.getEmpSalary()-e2.getEmpSalary())*10)).limit(1).forEach(e->System.out.println(e.getEmpSalary()));
		
		//4.统计所有员工工资的平均值
		System.out.println("\n4.统计所有员工工资的平均值");
		System.out.println(list.stream().collect(Collectors.averagingDouble(Employee::getEmpSalary)).doubleValue());
//		Double d = list.stream().collect(Collectors.averagingDouble(Employee::getEmpSalary));
//		System.out.println(d);
		
		//5.显示目前处于休闲状态的员工人数
		System.out.println("\n5.显示目前处于休闲状态的员工人数");
		System.out.println(list.stream().filter(e->e.getEmpStatus().equals("休闲")).map(e->e).collect(Collectors.toSet()).size());
		
		//6.查找所有离职员工的员工姓名并显示
		System.out.println("\n6.查找所有离职员工的员工姓名并显示");
		list.stream().filter(e->e.getEmpStatus().equals("离职")).forEach(e->System.out.println(e.getEmpName()));
		
		//7.查找所有姓王的员工并收集到一个set集合中
		System.out.println("\n7.查找所有姓王的员工并收集到一个set集合中");
		Set<Employee> set = list.stream().filter(e->e.getEmpName().startsWith("王")).map(e->e).collect(Collectors.toSet());
		System.out.println(set);
		
		//8.按照员工的状态信息对所有员工进行分组操作,并得到一个Map集合,遍历这个结果输出每种状态的各自人数
		System.out.println("\n8.按照员工的状态信息对所有员工进行分组操作,并得到一个Map集合,遍历这个结果输出每种状态的各自人数");
		Map<String, List<Employee>> map = list.stream().collect(Collectors.groupingBy(Employee::getEmpStatus));
		System.out.println("繁忙状态人数" + map.get("繁忙").size());
		System.out.println("休闲状态人数" + map.get("休闲").size());
		System.out.println("离职状态人数" + map.get("离职").size());
		
	}
	
}

终止操作:不再返回一个Stream流对象

allMatch:检查集合中元素是否都匹配

boolean b1 = list.stream().allMatch(s->s.getAge()>=18);//检查是否都成年了

anyMatch:检查是否至少有一个匹配元素

boolean b2 = list.stream().anyMatch(s->s.getScore()==100);

findFirst()返回第一个元素

//找到成绩最高的学生
Optional<Student> s = list.stream().sorted((s1,s2)->-Double.compare(s1.getScore(), s2.getScore())).limit(1)
		.findFirst();//将可能为空的结果封装到Optional类中
		
Student student = s.get();//获取对象时如果不存在则抛出No value present异常,比传统的空指向异常更容易定位

System.out.println(student.getName());
Optional也是一个容器类,代表里面的值存在或不存在,传统的程序中是用null来表示一个对象不存在,主要作用是避免和减少程序中的空指向异常

max():获取最大值

min():获取最小值

count():计数

//查找分数最高的学生
Optional<Student> max = list.stream().max((s1,s2)->Double.compare(s1.getScore(), s2.getScore()));
try {
    Student s= max.get();
    System.out.println(s);
}catch (Exception e) {
    // TODO: handle exception
}
//查找最低的分数
Optional<Double> min = list.stream().map(Student::getScore).min(Double::compare);
System.out.println(min.get());
//统计及格的人数
long count = list.stream().filter(s->s.getScore()>=60).count();//一定有结果,无需封装成optional
System.out.println(count);

需求:想要计算总分,没有直接提供sum

reduce:将流中的元素反复结合起来进行指定的运算

Optional<Double> total1 = list.stream().map(Student::getScore).reduce((x,y)->x+y);
Optional<Double> total2 = list.stream().map(Student::getScore).reduce(Double::sum);
System.out.println(total1.get());
System.out.println(total2.get());

collect()接收一个Collector接口收集器参数并将流处理的结果收集到指定的容器中

Collector接口的实现决定了将处理结果收集到List Set还是其他的一些容器中,我们一般不会直接创建接口对象,而是借助Collectors工具类提供的静态方法来获得一个收集器实例

//提取所有的学生姓名并收集到一个List中		
List<String> result = list.stream().map(Student::getName).collect(Collectors.toList());
System.out.println(result);		
//提取所有的学生姓名并收集到一个Set中
Set<String> result2 = list.stream().map(Student::getName).collect(Collectors.toSet());
System.out.println(result2);//排重
//如果想要收集结果到一些特殊的容器中比如LinkedHashSet
LinkedHashSet<String> result3 = list.stream().map(Student::getName).collect(Collectors.toCollection(LinkedHashSet::new));
System.out.println(result3);

Collectors还提供了对于单个统计结果的常用收集器

//统计及格人数
Long count = list.stream().filter(s->s.getScore()>=60).collect(Collectors.counting());
System.out.println(count);

//统计平均分
Double avg = list.stream().collect(Collectors.averagingDouble(Student::getScore));
System.out.println(avg);

//获取年龄最大的学生
Optional<Student> op = list.stream().collect(Collectors.maxBy((s1,s2)->Integer.compare(s1.getAge(), s2.getAge())));
System.out.println(op.get());

Collectors工具类还支持集合的分组操作:

//按照指定的属性进行分组并得到一个map集合
Map<String, List<Student>> map = list.stream().collect(Collectors.groupingBy(Student::getGender));
System.out.println(map.size());		
//按照成绩将所有学生分为及格和不及格的两个区
Map<Boolean, List<Student>> map2 = list.stream().collect(Collectors.partitioningBy(s->s.getScore()>=60));
System.out.println(map2);		
//分组后再分别汇总
//统计及格和不及格分别的人数
Map<Boolean, Long> result = list.stream().collect(Collectors.partitioningBy(s->s.getScore()>=60,Collectors.counting()));
System.out.println(result);
//等性别分组后去两个性别中工资最高的
Map<String, Employee> collect = list.stream().collect(Collectors.groupingBy(
                (param -> param.getEmpGender()), HashMap::new, Collectors.collectingAndThen(Collectors.maxBy((p1, p2) -> Double.compare(p1.getEmpSalary(), p2.getEmpSalary())), Optional::get)));
System.out.println(collect);
//对性别和状态两种进行分组,然后取这几种中工资最高的
Map<BaseEmployee, Employee> collect1 = list.stream().collect(Collectors.groupingBy(
        (param -> BaseEmployee.builder().empGender(param.getEmpGender()).empStatus(param.getEmpStatus()).build()),
        HashMap::new,
        Collectors.collectingAndThen(Collectors.maxBy((p1, p2) -> Double.compare(p1.getEmpSalary(), p2.getEmpSalary())), Optional::get)));
System.out.println(collect1);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值