Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式。Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作,在新版的JPA中,也已经加入了Stream。
1.Stream 关注的是对集合的计算,主要和CPU 打交道
- 集合关注的是数据的存储,主要与内存打交道
2.特点
- Stream,自己不会存储元素
- Stream,不会改变原对象,相反,他们会返回一个持有结果的新Stream
- stream,是延迟执行,这意味着他们会等到需要结果的时候才会执行
3.Stream执行流程
- 1.Stream实例化
- 2.中间一些列操作(过滤,映射…等)
- 3.终止操作
4.说明:
- 中间操作:一个操作的中间链,对数据源的数据进行操作。
- 终止操作:一但执行终止操作,就会执行中间操作链,并产生结果。之后不会在被使用
- 要注意的是,对流的操作完成后需要进行关闭操作(或者用JAVA7的try-with-resources)。
一.创建Stream实例化
package com.yzh;
import com.yzh.controller.lambad.Person;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.thymeleaf.util.ArrayUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* @author
* 1.Stream 关注的是对集合的计算,主要和CPU 打交道
* 集合关注的是数据的存储,主要与内存打交道
*
* 2.特点
* Stream,自己不会存储元素
* Stream,不会改变原对象,相反,他们会返回一个持有结果的新Stream
* stream,是延迟执行,这意味着他们会等到需要结果的时候才会执行
*
* 3.Stream执行流程
* 1.Stream实例化
* 2.中间一些列操作(过滤,映射....等)
* 3.终止操作
*
* 4.说明:
* 中间操作:一个操作的中间链,对数据源的数据进行操作。
* 终止操作:一但执行终止操作,就会执行中间操作链,并产生结果。之后不会在被使用
* 要注意的是,对流的操作完成后需要进行关闭操作(或者用JAVA7的try-with-resources)。
*
*/
@SpringBootTest
class SpringSecruityApplicationTests {
/**
* 创建方式一: 通过集合的方式
*/
@Test
void contextLoads() {
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
//返回一个顺序流
Stream<Person> stream = personList.stream();
//返回一个并行流
Stream<Person> personStream = personList.parallelStream();
}
/**
* 创建方式二:通过数组的方式
*
* 调用用Arrays.stream()方法,还可以使用Stream将需要的数组转成Stream。
* 这个方法不但支持传入数组,将数组转成Stream,也支持传入多个参数,将参数最终转成Stream
*/
@Test
void StreamTest(){
Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
Stream<Integer> stream = Arrays.stream(array);
}
/**
* 创建方式三,通过类类本身 通过 Stream 的 of()
* Stream.of()
*/
@Test
void StreamTest03(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
}
}
2.中间件的
1.筛选与切片
/**
* 1.筛选与切片
*/
@Test
void streamTest(){
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("eee",274,"美dd国",'M'));
personList.add(new Person("eee",274,"美dd国",'M'));
personList.add(new Person("eee",274,"美dd国",'M'));
// filter(Predicate p):接收Lambda,从流中排除某些操作;
//查询年龄小于24的
personList.stream().filter(p->p.getAge()<24).forEach(System.out::println);
System.out.println("******************");
// limit:截断流,使其元素不超过给定对象
//前1条数据
personList.stream().limit(1).forEach(System.out::println);
System.out.println("******************");
// skip(n):跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
//跳过前两条数据
personList.stream().skip(2).forEach(System.out::println);
System.out.println("******************555");
// distinct:筛选,通过流所生成元素的hashCode()和equals()去除重复元素。
//去重,如果是自己创建的类一定要实现hashCode()和equals()
personList.stream().distinct().forEach(System.out::println);
}
2.Stream中间操作–映射
/**
* Stream中间操作--映射
*/
@Test
void test2() {
// map--接收Lambda,将元素转换成其他形式或提取信息。
// 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
//把集合中的字符串变成大写,把每个元素应用到toUpperCase()转成大写的函数上
List<String> list = Arrays.asList("aa", "bb");
list.stream().map(str->str.toUpperCase()).forEach(System.out::println);
System.out.println("测试**********");
//获取名字长度大于3的
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪的订单",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Tom",24,"美国",'M'));
// flatMap--接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
Stream<String> name = personList.stream().map(Person::getName);
name.filter(n->n.length()>3).forEach(System.out::println);
}
3.Stream中间操作–排序
/**
* Stream中间操作--排序
* sorted()--自然排序(Comparable)
* sorted(Comparator com)--定制排序(Comparator)
*/
@Test
void test3() {
//sorted()--自然排序(Comparable)
List<Integer> list = Arrays.asList(1, 9, 8, 6, 7, 2, 40, 50, -1);
list.stream().sorted().forEach(System.out::println);
//sorted(Comparator com)--定制排序(Comparator)
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪的订单",18,"中国",'F'));
personList.add(new Person("Tom",2,"美国",'M'));
personList.add(new Person("Tom",6,"美国",'M'));
//定制排序按照age排序
personList.stream().sorted((age1, age2) -> {
return Integer.compare(age1.getAge(), age2.getAge());
}).forEach(System.out::println);
}
5、终止操作–
1.查找与匹配 计算
/**
* @author 于振华
* @create 2020-06-20 23:12
* 5、终止操作--查找与匹配
* allMatch--检查是否匹配所有元素
* anyMatch--检查是否至少匹配一个元素
* noneMatch--检查是否没有匹配所有元素
* findFirst--返回第一个元素
* findAny--返回当前流中的任意元素
* count--返回流中元素的总个数
* max--返回流中最大值
* min--返回流中最小值
*/
public class StreamTest3 {
@Test
void test1() {
//查找与匹配
// allMatch--检查是否匹配 所有 元素
//练习是否所有员工年龄大于18岁
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪的订单",18,"中国",'F'));
personList.add(new Person("Tom",2,"美国",'M'));
personList.add(new Person("Tom",6,"美国",'M'));
boolean b = personList.stream().allMatch(e -> e.getAge() > 18);
System.out.println(b);//false
// anyMatch--检查是否 至少匹配 一个元素
//练习是否集合中至少有一个匹配,或多个匹配的元素
boolean b1 = personList.stream().anyMatch(e -> e.getAge() > 6);
System.out.println(b1+"----anyMatch");//true
// noneMatch--检查 是否 没有 匹配所有元素 ,
//练习检查是否存没有性T的员工,如果有返回false,没有true
//startsWith 指定前缀
boolean tome = personList.stream().noneMatch(e -> e.getName().startsWith("c"));
System.out.println(tome);//true
// findFirst--返回第一个元素
Optional<Person> first = personList.stream().findFirst();
System.out.println(first);//第一个元素
// findAny--返回当前流中的任意元素
//注意使用并行流
Optional<Person> any = personList.parallelStream().findAny();
System.out.println(any);
// count--返回流中元素的总个数
//练习年龄大于2 的总数
long count = personList.stream().filter(a -> a.getAge() > 2).count();
System.out.println("年龄大于2:"+count);
// max--返回流中最大值
//练习最大年龄
Optional<Integer> age = personList.stream().map(Person::getAge).max(Integer::compareTo);
System.out.println("最大年龄"+age);
// min--返回流中最小值
//练习最小的年龄
Optional<Person> min = personList.stream().min((a1, a2) -> Integer.compare(a1.getAge(), a2.getAge()));
System.out.println("最小的年龄:"+min);
//forEach(Consumer c)--内部迭代
personList.stream().forEach(System.out::println);
// 分数的最大值 最小值
Student max = students.stream().max(Comparator.comparing(Student::getScore)).orElse(null);
Student min = students.stream().min(Comparator.comparing(Student::getScore)).orElse(null);
//Student(name=小潘, age=19, clazz=高三4班, score=100, course=英语)
//Student(name=小李, age=16, clazz=高一3班, score=12, course=数学)
// 也可以通过如下写法获取最大值,这种写法只能获取到值,没法关联用户,跟上面的写法各有用途
int max2 = students.stream().mapToInt(Student::getScore).max().orElse(0);
int min2 = students.stream().mapToInt(Student::getScore).min().orElse(0);
System.out.println(max);
System.out.println(min);
}
}
1.1总结统计,计算(总数,平均值,最大,最小)
//summaryStatistics() 总结统计
public static void main(String[] args) {
List<Student> list = new ArrayList();
list.add(new Student("测试", "男", 10));
list.add(new Student("开发", "男", 20));
list.add(new Student("运维", "女", 10));
list.add(new Student("DBA", "女", 20));
//按性别进行分组统计人数
Map<String, Integer> map = list.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.summingInt(p -> 1)));
System.out.println(map);
//总结统计
IntSummaryStatistics intSummaryStatistics = list.stream().mapToInt(Student::getAge).summaryStatistics();
System.out.println(intSummaryStatistics);
System.out.println(intSummaryStatistics.getMax());//最大
System.out.println(intSummaryStatistics.getCount());//总数
}
2.规约操作
/**
* 规约操作
*/
@Test
void test2(){
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪的订单",18,"中国",'F'));
personList.add(new Person("Tom",2,"美国",'M'));
personList.add(new Person("Tom",6,"美国",'M'));
//reduce 操作可以实现从Stream中生成一个值,其生成的值不是随意的,而是根据指定的计算模型。比如,之前提到count、min和max方
//法,因为常用而被纳入标准库中。事实上,这些方法都是reduce操作。
//Optional<T> reduce(BinaryOperator<T> accumulator);
//计算员工年龄总和
Optional<Integer> sumAge = personList.stream().map(Person::getAge).reduce(Integer::sum);
Optional<Integer> sumAge2 = personList.stream().map(Person::getAge).reduce((a1,a2)->a1+a2);
System.out.println(sumAge);
System.out.println(sumAge2+"************A2");
//T reduce(T identity, BinaryOperator<T> accumulator);
//练习1-10自然数之间的和
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//0是初始值 0+1+2+3....
Integer sum = integers.stream().reduce(0, Integer::sum);
System.out.println(sum);
}
2.1 集合计算
static List<Employee> list = new ArrayList<Employee>();
private static void initEmp(){
list .add(new Employee("张",3));
list .add(new Employee("张1",6));
list .add(new Employee("张2",3));
list .add(new Employee("张3",9));
}
//获取员工年龄的最大、最小、总和、平均值
public static void main(String[] args) {
initEmp();
int sum = list .stream().mapToInt(Employee->Employee.getAge()).sum();
int max = list .stream().mapToInt(Employee->Employee.getAge()).max().getAsInt();
int min = list .stream().mapToInt(Employee->Employee.getAge()).min().getAsInt();
double avg = list .stream().mapToInt(Employee->Employee.getAge()).average().getAsDouble();
System.out.println("最大值:"+max+"\n最小值:"+min+"\n总和:"+sum+"\n平均值:"+avg);
3 收集操作
/**
* 3 收集操作
* collect:接收一个Collector实例,将流中元素收集成另外一个数据结构。
*/
@Test
void test3() {
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪的订单",18,"中国",'F'));
personList.add(new Person("Tom",2,"美国",'M'));
personList.add(new Person("Tom",6,"美国",'M'));
//练习,查找年龄大于2的元素,并且返回List
List<Person> collect = personList.stream().filter(e -> e.getAge() > 2).collect(Collectors.toList());
collect.forEach(System.out::println);
//练习,查找年龄大于2的元素,并且返回Set
Set<Person> collect1 = personList.stream().filter(e -> e.getAge() > 2).collect(Collectors.toSet());
collect1.forEach(System.out::println);
//练习,查找年龄大于2的元素,并且返回Collection
}
去重
list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(v -> v.getLocation()))), ArrayList::new));