Jdk8——Stream API,创建、中间操作、终止操作详细说明

强大的Stream API


1. Stream API说明
  • Java8中最重要的两个改变一个是Lambda表达式,一个则是Stream API

  • Stream API(java.util.stream)把真正的函数式编程风格引入Java中,这是目前为止Java类库最好的补充,因为Stream API可以极大的提供Java程序员的生产力,让程序员写出更高效、干净、优美、简洁的代码。

  • Stream 是Java8中处理集合的关键概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于SQL执行数据库的查询。也可以使用Stream API来并行操作。简而言之,Stram API 提供了一种高效且易于使用的处理数据的方式。

  • 持久层数据库,比如Mysql、Oracle等,相当于是在数据库层面进行数据的操作,但是随着MongDB、Radis等NoSQL数据库的出现,就需要在Java层面进行数据的操作了。这个时候使用Steam API

  • Stream 和 Collection 集合的区别:Collection是一种静态的内存结构。而Stream是有关计算的。前者主要是面向内存,存储在内存中,后者主要是面向CPU,案通过CPU实现计算。

集合将的是数据,Stream讲的是计算。
(1)Stream自己不会存储元素。
(2)Stream不会改变源对象,相反他们会返回一个持有结果到新的Stream中。
(3)Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。

2、创建Stream(Stream的实例化)

一个数据源(如:集合、数组),获取一个流

  1. 集合创建Stream
@Test
public void test(){
    
    
	//获取一个集合
	List<Employee> list = EmplpyeeData.getEmployees();
	
	//default Stream<E> stream(); 返回一个顺序流
	Stream<Employee> stream = list.stream();
	
	//default Stream<E> parallelStream(); 返回一个并行流
	Stream<Employee> parallelStream = list.parallelStream();
}
  1. 数组创建Stream
@Test
public void test(){
    
    
	int[] arr = new int[]{
    
    1,2,3,4,5,6};
	//调用Arrays类的static<T> Stream<T> stream(T[] array);返回一个流
	Instream stream = Arrays.stream(arr);

	Employee e1 = new Employee("1001","Tom");
	Employee e2 = new Employee("1002","Marry");
	Employee[] arr1 = new Employee[]{
    
    e1,e2};
	Stream<Employee> stream1 = Arrays.stream(arr1);
}
  1. 通过Stream的 of() 创建Stream
@Test
public void test(){
    
    
	Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
}
  1. 创建无限流(不常用)
  • 帮我们创造数据时候使用
@Test
public void test(){
    
    

	//迭代
	//public static<T> Stream<T> iterate(final T seed,final UnaryOperator<T> f);
	//遍历前10个偶数(不会停下来)
	Stream.iterate(0,t -> t + 2).forEach(System.out::println);
	//加上限制,只要前十个偶数
	Stream.iterate(0,t -> t + 2)limit(10).forEach(System.out::println);
	
	//生成
	//public static<T> Stream<T> generate(Supplier<T> s);
	Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
3、中间操作(过滤、映射、排序)

一个中间操作链,对数据源的数据进行处理。

  1. 筛选与切片
@Test
public void test(){
    
    
	List<Employee> list = EmployeeData.getEmployees();

	//filter(Predicate p) 接收 Lambda ,从流中排除某些元素
	Stream<Employee> stream = list.stream();
	//查询员工表中薪资>7000的员工信息
	stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);
	//截断流 注意需要冲洗生成流,因为之前已经进行了终止操作
	//是元素不超过给定的数量
	list.stream().limit(3).forEach(System.out::println);
	//skip(n) 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个Null
	list。stream().skip(20).forEach(System.out::println);
	//distinct() 筛选,通过流所生成元素的hashCode()和equals()去除重复元素
	list.stream().distinct().forEach(System.out::println);
}
  1. 映射
  @Test
    public void test13(){
    
    
		
        List<String> list = Arrays.asList("abc","def","cbd","aaa");
        //map(Function f) 接收一个函数作为参数,该函数提供了某种规则,通过这种规则将原有集合的数据映射到一个新的集合中。
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);

	//练习:获取员工姓名大于三的员工姓名
	List<Emplouyee> list = employeeData.getEmplyees();
	//Stream<String> nameStream = list.stream.map(e -> e.getName());
	Stream<String> nameStream = list.stream.map(Employee :: getName);
	nameStream.filter(name ->name.length()>3).forEach(System.out::println);
    }
	
@Test
public void test(){
    
    
	//flatMap(Function f) 接受一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有流连接成一个流。
	//练习:
	//集合里面套集合的情况时,遍历每一个元素。
	//用map来做
	//注意:StreamAPITest是类名,使用类名::静态方法
	Stream<Stream<Charcator>> streamStream = list.stream().map(StreamAPITest :: fromStringtoStream);
	streamStream.forEach(s ->{
    
    
		s.forEach(System.out::println)
	});	
	//用flatMap来做
	Stream<Charactor> charactorStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
	charactorStream.forEach(System.out::println);
}
public static Stream<Charcater> fromStringToStream(String str){
    
    
	ArrayList<Character> list = new ArrayList<>();
	for(Charactor c : str.toCharArray()){
    
    
		list.add(c);
	}
	return list.stream();
}

  1. 排序
@Test
public void test(){
    
    

	//sorted() 自然排序
	List<Integer> list = Arrays.asList(1,2412,3423,54,3234,645,1,212,-13,11);
	list.stream().sorted().forEach(System.out::println);

	//对象的排序,sorted(Comparator com) 定制排序
	//需要实现接口
	List<Employee> list = employeeData.getEmployees();
	list.stream().sorted((e1,e2) -> {
    
    
		int ageValue = Integer.compare(e1.getAge(),e2.getAge());
		//按照年龄进行排序,如果年龄相等按照工资进行排序
		if(ageValue != 0){
    
    
			return ageValue;
		}else{
    
    
			return - Double.compare(e1.getSalary(),e2.getSalary());
		}	
	}).forEach(System.out::println);
}
4、终止操作(终端操作)

一旦执行终止操作,就执行中间操作链,并产生结果,之后,不会再被使用。如果想再用需要重新创建一个Stream流

  1. 匹配与查找
List<Employee> list = EmployeeData.getEmployees();
//allMatch(Predicate p) 检查是否匹配所有元素
//练习:是否所有员工的年龄都大于18
boolean allMatch = list.stream().allMatch(e -> e.getAge() > 18);

//anyMatch(Predicate p) 检查是否至少匹配一个元素。
//练习:是否存在员工的工资大于10000
boolean anyMatch = list.stream().anyMatch(e -> e.getSalary() > 10000);

//noneMatch(Predicate p) 检查是否没有匹配的元素,有返回false,没有返回true
//练习:是否存在员工姓”雷“ 
boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startWitch("雷"))//findFirst()返回第一个元素,可以结合排序来写

//findAny() 返回当前流中的任意元素

//count() 返回流中元素的总个数
long count = list.stream().filte(e -> e.getSalary() > 5000).count();

//max(Comparator c) 返回流中最大值
//练习 求员工中最高工资
//使用map先映射到工资...
Stream<Double> salaryStream = employees.stream().map(e - >e.getSalary());
Optional<Double> maxSalary = salarySaream.max(Double :: compare);

//min(Comparator c) 返回流中最小值
//求最低工资的员工信息
Optional<Employee> employee = list.stream().min((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary()));

//forEach(Cousumer c) 内部迭代
list.stream().forEach(System.out::println);
//注意与集合中的forEach()进行区分
list.forEach(System.out::println);
  • 外部迭代类似于之前的Iterator ,指针在外部指向集合,需要调用next()方法将指针下移,而内部迭代,相当于是在集合内部自动进行的。
  1. 规约
@Test
public void test14(){
    
    

    //T reduce(T identity, BinaryOperator<T> accumulator); 可以将流中元素反复结合起来,得到一个值,返回一个T
	List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
	Integer reduce = list.stream().reduce(0, Integer::sum);
	System.out.println(reduce);
	
	//Optional<T> reduce(BinaryOperator<T> accumulator); 可以将流中元素反复结合起来得到一个值,返回Optional<T>
	//计算公司中所有员工工资的总和
	List<Employee> list = EmployeeData.getEmployees();
	Stream<Double> salaryStream = list.stream().map(Employee :: getSalary);
	Optional<Employee> countMoney = salaryStream.reduce(Double :: sum);
	
	//或者也可以自己写累加
	Optional<Employee> countMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
}
  1. 收集
@Test
public void test(){
    
    
	
	//collect(Collector c) 将流转化为其他形式,接收一个Collector接口的实现,用于
	List<Employee> list = EmployeeData.getEmployees();
	//将工资中大于6000的放到一个list中
	List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
	employeeList.forEach(System.out::println);
	
	//也可以放到一个set集合中,只需要调用Collectors中写好的静态方法就可以了
	List<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
	employeeSet.forEach(System.out::println);
}
  • Collectors内部静态方法
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43941676/article/details/108547305