最新消息: 电脑我帮您提供丰富的电脑知识,编程学习,软件下载,win7系统下载。

Java8新特性:Stream详细使用

IT培训 admin 7浏览 0评论

Java8新特性:Stream详细使用

目录

    • 一、简介
    • 二、创建Stream的常用方法
      • 2.1 使用Stream中的静态方法:of()、iterate()、generate()
      • 2.2 使用Collection下的 stream() 和 parallelStream() 方法
      • 2.3 使用Arrays 中的 stream() 方法,将数组转成流
      • 2.4 使用BufferedReader.lines() 方法
    • 三、中间操作符(Intermediate operations)
      • 3.1 无状态(Stateless)
        • 3.1.1 filter - 过滤操作
        • 3.1.2 map - 映射、转换操作
        • 3.1.3 flatmap - 映射、转换操作
        • 3.1.4 peek - 挑出操作
      • 3.2 有状态(Stateful)
        • 3.2.1 distinct - 去重操作
        • 3.2.2 sorted - 自然排序
        • 3.2.3 sorted(Comparator com) - 指定排序
        • 3.2.4 limit - 限流操作
        • 3.2.5 skip - 跳过操作
    • 四、终结操作符(Terminal operations)
      • 4.1 非短路操作
        • 4.1.1 forEach - 遍历操作
        • 4.1.2 forEachOrdered - 遍历操作
        • 4.1.3 toArray - 数组操作
        • 4.1.4 reduce - 规约操作
        • 4.1.5 collect - 收集操作
        • 4.1.6 max - 最大值操作
        • 4.1.7 min - 最小值操作
        • 4.1.8 count - 统计操作
      • 4.2 短路操作(short-circuiting)
        • 4.2.1 anyMatch - 匹配操作(任意一个匹配)
        • 4.2.2 allMatch - 匹配操作(所有都匹配)
        • 4.2.3 noneMatch - 匹配操作(没有一个匹配)
        • 4.2.4 findFirst - 查找操作(找第一个)
        • 4.2.5 findAny - 查找操作(找任意一个)
    • 结语

一、简介

  Java 8 API 添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据,类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API 将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如查找,过滤, 排序,聚合等等操作。Stream API可以极大提高Java程序员的工作效率,让代码更简洁,干净。

  • Stream本身不会存储元素
  • Stream不会改变数据源对象,相反会返回产生一个持有结果的新Stream
  • Steam操作是延迟执行的,这意味着他们会等到需要结果的时候才执行

二、创建Stream的常用方法

2.1 使用Stream中的静态方法:of()、iterate()、generate()

    @Testpublic void stream(){//1.1传入可变参数,字符串,数字等Stream<String> stringStream = Stream.of("Alian", "boy", "cat", "papa");//1.2传入对象Stream<User> userStream = Stream.of(new User("BAT031", "胡一菲", "销售部", 28, 3500));//2.1generate方法参数为Function<T, T>函数型接口的子类,比如产生正奇数Stream<Integer> oddStream = Stream.iterate(1, (x) -> x + 2);oddStream.limit(5).forEach(System.out::println);//3.1generate方法参数为Supplier<T> 供给型接口,比如生成1-1000的随机数:(int) Math.round(Math.random() * (m - n) + n)Stream<Integer> generateStream = Stream.generate(() -> (int) Math.round(Math.random() * (1000 - 1) + 1));generateStream.limit(10).forEach(System.out::println);//打印10个随机数}

2.2 使用Collection下的 stream() 和 parallelStream() 方法

stream是顺序流,parallelStream是并行流。

    @Testpublic void streamAndParallelStream(){//初始化一个list列表List<String> fruitList = Arrays.asList("apple","banana","orange","watermelon","pear");//获取一个顺序流Stream<String> stream = fruitList.stream();System.out.println("--------获取顺序流的结果-----------");stream.forEach(System.out::println);//获取一个并行流Stream<String> parallel = fruitList.parallelStream();System.out.println("--------获取并行流的结果-----------");parallel.forEach(System.out::println);}

运行结果:

--------获取顺序流的结果-----------
apple
banana
orange
watermelon
pear
--------获取并行流的结果-----------
orange
watermelon
banana
apple
pear

2.3 使用Arrays 中的 stream() 方法,将数组转成流

    @Testpublic void arraysToStream(){//初始化一个String数组(当然也可以去其他类型的数组)String[] animal = new String[]{"cat","dog","pig","chicken","duck"};Stream<String> animalStream = Arrays.stream(animal);animalStream.forEach(System.out::println);}

运行结果:

cat
dog
pig
chicken
duck

2.4 使用BufferedReader.lines() 方法

    @Testpublic void readLineStream() throws FileNotFoundException {//通过BufferedReader获取到一个流(要自己写一个文件哦,比如我这里的"C:\\myStream.txt")BufferedReader bufReader = new BufferedReader(new FileReader("C:\\myStream.txt"));Stream<String> lineStream = bufReader.lines();lineStream.forEach(System.out::println);}

运行结果:

我在使用Java 8 Stream API进行测试(BufferedReader.lines()方式获取流)

三、中间操作符(Intermediate operations)

3.1 无状态(Stateless)

3.1.1 filter - 过滤操作

  filter方法对原Stream按照指定条件过滤,在新建的Stream中,只包含满足条件的元素,将不满足条件的元素过滤掉。

    @Testpublic void filter() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT001", "胡昊天", "销售部", 28, 3500),new User("BAT002", "王大锤", "销售部", 27, 3000),new User("BAT003", "唐二鹏", "研发部", 32, 9900),new User("BAT004", "王一林", "研发部", 30, 9000));//过滤出用户表中年龄大于28岁的员工List<User> collect = userList.stream().filter(f -> f.getAge() > 28).collect(Collectors.toList());System.out.println("年龄大于28岁的员工信息:" + collect);//过滤出用户表中年龄大于28岁并且工资大于9000元的员工List<User> collect2 = userList.stream().filter(f -> (f.getAge() > 28 && f.getSalary() > 9000)).collect(Collectors.toList());System.out.println("年龄大于28岁并且工资大于9000元的员工信息:" + collect2);}

运行结果:

年龄大于28岁的员工信息:[User(id=BAT003, name=唐二鹏, age=32, department=研发部, salary=9900.0), User(id=BAT004, name=王一林, age=30, department=研发部, salary=9000.0)]
年龄大于28岁并且工资大于9000元的员工信息:[User(id=BAT003, name=唐二鹏, age=32, department=研发部, salary=9900.0)]

3.1.2 map - 映射、转换操作

  map接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。map方法将对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。

    @Testpublic void map() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//获取列表中员工的姓名(新生成的Stream只包含转换生成的元素)List<String> collect = userList.stream().map(User::getName).collect(Collectors.toList());System.out.println("获取到的员工姓名:" + collect);//mapToDoubleSystem.out.println("员工的工资都转成double:");userList.stream().mapToDouble(User::getSalary).forEach(System.out::println);//mapToIntSystem.out.println("员工的年龄都转成int:");userList.stream().mapToInt(User::getAge).forEach(System.out::println);}

运行结果:

获取到的员工姓名:[梁南生, 包雅馨, 罗考聪]
员工的工资都转成double:
8000.0
6000.0
7400.0
员工的年龄都转成int:
27
25
35

3.1.3 flatmap - 映射、转换操作

  flatmap接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流。每个部分流中的每个值成单独小流,再串成一个整体流。即对Stream中的每一个元素通过转换函数转换,不同的是,该换转函数的对象是一个Stream,也不会再创建一个新的Stream,而是将原Stream的元素取代为转换的Stream

    @Testpublic void flatMap() {//flatmap接收的参数是一个StreamSystem.out.println("一、把流中的短横线替换后输出的结果:");Stream.of("A-l-i-a-n ","l-o-v-e ","C-S-D-N").flatMap(e->Stream.of(e.split("-"))).forEach(System.out::print);System.out.println();System.out.println("二、把流中的每个数据乘以10的结果:");Stream.of(2,5,8,9).flatMap(n->Stream.of(n*10)).forEach(System.out::println);}

运行结果:

一、把流中的短横线替换后输出的结果:
Alian love CSDN
二、把流中的每个数据乘以10的结果:
20
50
80
90

3.1.4 peek - 挑出操作

  peek方法和map一样能得到流中的每一个元素,只不过map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。peek方法会生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数,并且消费函数优先执行。

    @Testpublic void peek() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT008", "张伟杰", "测试部", 24, 7000),new User("BAT009", "胡俊伟", "研发部", 24, 4500));List<User> collect = userList.stream().peek(p -> p.setDepartment("运维部")).collect(Collectors.toList());System.out.println("部门都改为运维部:"+collect);}

运行结果:

部门都改为运维部后的信息:[User(id=BAT008, name=张伟杰, age=24, department=运维部, salary=7000.0), User(id=BAT009, name=胡俊伟, age=24, department=运维部, salary=4500.0)]

3.2 有状态(Stateful)

3.2.1 distinct - 去重操作

  distinct方法对原Stream中重复的元素进行剔除,生成的新Stream中没有没有重复的元素。

    @Testpublic void distinct() {System.out.println("按照类型去重结果:");Stream.of(3, 6, 9, 3, 9, 5).distinct().forEach(System.out::println);List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000));System.out.println("按照对象去重结果:");userList.stream().distinct().forEach(System.out::println);}

运行结果:

按照类型去重结果:
3
6
9
5
按照对象去重结果:
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)

3.2.2 sorted - 自然排序

sorted方法将对原Stream进行排序,返回一个有序的新Stream。

    @Testpublic void sorted() {//自然排序结果System.out.println("数字自然排序结果:");Stream.of(15, 28, 6, 9).sorted().forEach(System.out::println);System.out.println("字符自然排序结果:");Stream.of("b", "ab", "ba", "c").sorted().forEach(System.out::println);}

运行结果:

数字自然排序结果:
6
9
15
28
字符自然排序结果:
ab
b
ba
c

3.2.3 sorted(Comparator com) - 指定排序

sorted(Comparator)方法接收一个自定义排序规则函数(Comparator)。

    @Testpublic void sortedWithCompare() {List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//按照年龄升序排序System.out.println("按照年龄升序排序");userList.stream().sorted(Comparator.comparingInt(User::getAge)).forEach(System.out::println);//按照年龄倒序排序System.out.println("按照年龄倒序排序");userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).forEach(System.out::println);}

运行结果:

按照年龄升序排序
User(id=BAT012, name=张萌萌, age=20, department=行政部, salary=3500.0)
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)
按照年龄倒序排序
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)
User(id=BAT012, name=张萌萌, age=20, department=行政部, salary=3500.0)

3.2.4 limit - 限流操作

limit(n)方法限制从流中获得前n个数据。

    @Testpublic void limit() {List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//按照年龄倒序排序后取前面两条记录System.out.println("按照年龄倒序排序后取前面两条记录:");userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).limit(2).forEach(System.out::println);}

运行结果:

按照年龄倒序排序后取前面两条记录:
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)

3.2.5 skip - 跳过操作

skip(n)方法跳过n元素可以配合limit进行操作。

    @Testpublic void skip() {List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//按照年龄倒序排序后取前面两条记录System.out.println("按照年龄倒序排序后跳过一条数据取两条记录:");userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).skip(1).limit(2).forEach(System.out::println);}

运行结果:

按照年龄倒序排序后跳过一条数据取两条记录:
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)
User(id=BAT012, name=张萌萌, age=20, department=行政部, salary=3500.0)

四、终结操作符(Terminal operations)

4.1 非短路操作

4.1.1 forEach - 遍历操作

forEach方法前面已经用了好多次,其用于遍历Stream中的所元素,顺序流下按照插入数据的顺序进行输出,并行流的时候是随机输出的。

    @Testpublic void forEach() {//初始化一个数据列表List<Integer> list = Arrays.asList(2, 3, 4, 5, 6);System.out.println("顺序流下输出:");list.stream().sorted().forEach(f -> System.out.println("forEach顺序流下数据:" + f));System.out.println("并行流下输出:");list.parallelStream().forEach(f -> System.out.println("forEach并行流下数据:" + f));List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//按照年龄倒序排序后取前面两条记录System.out.println("跳过前面一条数据后输出:");userList.stream().skip(1).forEach(System.out::println);}

运行结果:

顺序流下输出:
forEach顺序流下数据:2
forEach顺序流下数据:3
forEach顺序流下数据:4
forEach顺序流下数据:5
forEach顺序流下数据:6
并行流下输出:
forEach并行流下数据:4
forEach并行流下数据:6
forEach并行流下数据:5
forEach并行流下数据:2
forEach并行流下数据:3
跳过前面一条数据后输出:
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)
User(id=BAT012, name=张萌萌, age=20, department=行政部, salary=3500.0)

4.1.2 forEachOrdered - 遍历操作

forEachOrdered方法与forEach类似,都是遍历Stream中的所有元素,不同的是,如果该Stream预先设定了顺序,会按照预先设定的顺序执行(Stream是无序的),默认为元素插入的顺序。顺序流下按照插入数据的顺序进行输出,并行流的时候流的遇到顺序得到保持。

    @Testpublic void forEachOrdered() {List<Integer> list = Arrays.asList(2, 3, 4, 5, 6, 7);System.out.println("forEachOrdered顺序流下输出:");list.parallelStream().forEachOrdered(f -> System.out.println("forEachOrdered顺序流下数据:" + f));System.out.println();System.out.println("forEachOrdered并行流下输出(流的遇到顺序得到保持):");list.parallelStream().forEachOrdered(f -> System.out.println("forEachOrdered并行流下数据:" + f));}

运行结果:

forEachOrdered顺序流下输出:
forEachOrdered顺序流下数据:2
forEachOrdered顺序流下数据:3
forEachOrdered顺序流下数据:4
forEachOrdered顺序流下数据:5
forEachOrdered顺序流下数据:6
forEachOrdered顺序流下数据:7forEachOrdered并行流下输出(流的遇到顺序得到保持):
forEachOrdered并行流下数据:2
forEachOrdered并行流下数据:3
forEachOrdered并行流下数据:4
forEachOrdered并行流下数据:5
forEachOrdered并行流下数据:6
forEachOrdered并行流下数据:7

4.1.3 toArray - 数组操作

toArray 转成数组,也可以提供自定义数组生成器

    @Testpublic void toArray() {Object[] animal= Stream.of("cat", "dog", "pig", "chicken", "duck").toArray();for(Object a:animal){System.out.println("数组里有:"+a);}}

运行结果:

数组里有:cat
数组里有:dog
数组里有:pig
数组里有:chicken
数组里有:duck

4.1.4 reduce - 规约操作

reduce方法是一个规约操作,所有的元素归约成一个。比如对所有元素求和,乘积等。这里实现了一个求和和乘积的方法,并指定了初始化的值分别为0和1(乘法指定1开始,不然没有意义).

    @Testpublic void reduce() {int sum = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).reduce(0, Integer::sum);System.out.println("1到10的和等于:" + sum);int product = Stream.of(1, 2, 3, 4, 5).reduce(1, (e1, e2) -> e1 * e2);System.out.println("1到5的乘积等于:" + product);}

运行结果:

1到10的和等于:55
1到5的乘积等于:120

4.1.5 collect - 收集操作

collect 操作我们也使用了很多次了,就不过多详细介绍了

@Testpublic void collect() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT004", "王一林", "研发部", 30, 9000),new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//按年龄排序后转为listSystem.out.println("----------转list后的结果----------");userList.stream().sorted(Comparator.comparingInt(User::getAge)).collect(Collectors.toList()).forEach(System.out::println);//按工资排序后转为setSystem.out.println("----------转set后的结果----------");userList.stream().sorted(Comparator.comparingDouble(User::getSalary)).collect(Collectors.toCollection(LinkedHashSet::new)).forEach(System.out::println);//以员工的编号做为key,员工信息作为value转换为mapSystem.out.println("----------以员工的编号做为key,员工信息作为value转换为map----------");Map<String, User> collect = userList.stream().collect(Collectors.toMap(User::getId, u -> u));collect.forEach((x, y) -> System.out.println(x + "->" + y));//把名字用逗号分隔System.out.println("----------名字拼接后结果----------");String nameStr = userList.stream().map(User::getName).collect(Collectors.joining(","));System.out.println(nameStr);System.out.println("----------按部门分组统计----------");//按部门进行分组统计人数Map<String, Long> groupingBy = userList.stream().collect(Collectors.groupingBy(User::getDepartment, Collectors.counting()));groupingBy.forEach((x, y) -> System.out.println(x + "->" + y));//获取工资汇总信息System.out.println("----------工资汇总信息----------");DoubleSummaryStatistics statistics = userList.stream().collect(Collectors.summarizingDouble(User::getSalary));System.out.println("最高工资:" + statistics.getMax());System.out.println("最低工资:" + statistics.getMin());System.out.println("工资总和:" + statistics.getSum());System.out.println("平局工资:" + statistics.getAverage());System.out.println("总记录数:" + statistics.getCount());}

运行结果:

----------转list后的结果----------
User(id=BAT006, name=包雅馨, age=25, department=财务部, salary=6000.0)
User(id=BAT005, name=梁南生, age=27, department=研发部, salary=8000.0)
User(id=BAT004, name=王一林, age=30, department=研发部, salary=9000.0)
User(id=BAT007, name=罗考聪, age=35, department=测试部, salary=7400.0)
----------转set后的结果----------
User(id=BAT006, name=包雅馨, age=25, department=财务部, salary=6000.0)
User(id=BAT007, name=罗考聪, age=35, department=测试部, salary=7400.0)
User(id=BAT005, name=梁南生, age=27, department=研发部, salary=8000.0)
User(id=BAT004, name=王一林, age=30, department=研发部, salary=9000.0)
----------以员工的编号做为key,员工信息作为value转换为map----------
BAT004->User(id=BAT004, name=王一林, age=30, department=研发部, salary=9000.0)
BAT007->User(id=BAT007, name=罗考聪, age=35, department=测试部, salary=7400.0)
BAT005->User(id=BAT005, name=梁南生, age=27, department=研发部, salary=8000.0)
BAT006->User(id=BAT006, name=包雅馨, age=25, department=财务部, salary=6000.0)
----------名字拼接后结果----------
王一林,梁南生,包雅馨,罗考聪
----------按部门分组统计----------
测试部->1
财务部->1
研发部->2
----------工资汇总信息----------
最高工资:9000.0
最低工资:6000.0
工资总和:30400.0
平局工资:7600.0
总记录数:4

4.1.6 max - 最大值操作

max方法根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最大的元素。

    @Testpublic void max() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//筛选出年龄最大的员工信息Optional<User> userOptional = userList.stream().max(Comparator.comparingInt(User::getAge));//只是演示此处不做判断了User user = userOptional.get();System.out.println("年龄最大的员工信息:" + user);}

运行结果:

年龄最大的员工信息:User(id=BAT007, name=罗考聪, age=35, department=测试部, salary=7400.0)

4.1.7 min - 最小值操作

min方法根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最小的元素。

    @Testpublic void min() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//筛选出工资最低的员工信息Optional<User> userOptional = userList.stream().min(Comparator.comparingDouble(User::getSalary));//只是演示此处不做判断了User user = userOptional.get();System.out.println("工资最低的员工信息:" + user);}

运行结果:

工资最低的员工信息:User(id=BAT006, name=包雅馨, age=25, department=财务部, salary=6000.0)

4.1.8 count - 统计操作

count方法将返回Stream中元素的个数,一般用于流中间操作后的统计。

    @Testpublic void count() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//统计年龄小于30的员工的个数long count = userList.stream().filter(f -> f.getAge() < 30).count();System.out.println("年龄小于30的员工的个数:" + count);}

运行结果:

年龄小于30的员工的个数:2	

4.2 短路操作(short-circuiting)

4.2.1 anyMatch - 匹配操作(任意一个匹配)

anyMatch方法按照指定的条件匹配到Stream中任意一个元素则返回true,否则返回false。

    @Testpublic void anyMatch() {List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包三雅", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400),new User("BAT008", "张伟杰", "测试部", 24, 7000));//匹配任意一个年龄大于35岁的员工boolean b = userList.stream().anyMatch(p -> p.getAge() > 35);System.out.println("匹配任意一个年龄大于34岁的员工:" + b);//匹配任意一个“张”姓的员工boolean flag = userList.stream().anyMatch(p -> p.getName().startsWith("张"));System.out.println("匹配任意一个“张”姓的员工:" + flag);}

运行结果:

匹配任意一个年龄大于34岁的员工:false
匹配任意一个“张”姓的员工:true

4.2.2 allMatch - 匹配操作(所有都匹配)

allMatch方法按照指定的条件匹配Stream中所有的元素才返回true,否则返回false。

    @Testpublic void allMatch() {List<User> userList = Arrays.asList(new User("BAT009", "胡俊伟", "研发部", 24, 4500),new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//匹配所有人年龄都大于22岁boolean b = userList.stream().allMatch(p -> p.getAge() > 22);System.out.println("所有人年龄都大于22岁:" + b);//匹配所有人年龄都大于18岁boolean flag = userList.stream().allMatch(p -> p.getAge() > 18);System.out.println("所有人年龄都大于18岁:" + flag);}

运行结果:

所有人年龄都大于22岁:false
所有人年龄都大于18岁:true

4.2.3 noneMatch - 匹配操作(没有一个匹配)

noneMatch方法按照指定的条件,Stream中没有一个元素匹配得上才返回true,否则返回false。

    @Testpublic void noneMatch() {List<User> userList = Arrays.asList(new User("BAT001", "胡昊天", "销售部", 28, 3500),new User("BAT002", "王大锤", "销售部", 27, 3000),new User("BAT003", "唐二鹏", "研发部", 32, 9900),new User("BAT004", "王一林", "研发部", 30, 9000),new User("BAT005", "梁南生", "研发部", 27, 8000));//匹配没有一个“李”姓员工boolean b = userList.stream().noneMatch(p -> p.getName().startsWith("李"));System.out.println("没有一个李姓员工:" + b);//匹配没有一个“胡”姓员工boolean flag = userList.stream().noneMatch(p -> p.getName().startsWith("胡"));System.out.println("没有一个胡姓员工:" + flag);}

运行结果:

没有一个李姓员工:true
没有一个胡姓员工:false

4.2.4 findFirst - 查找操作(找第一个)

findFirst方法用于获取Stream中的第一个元素的Optional,如果Stream为空,则返回一个空的Optional。

    @Testpublic void findFirst() {List<User> userList = Arrays.asList(new User("BAT003", "唐二鹏", "研发部", 32, 9900),new User("BAT004", "王一林", "研发部", 30, 9000),new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅欣", "财务部", 25, 6000));Optional<User> first = userList.stream().findFirst();System.out.println("查找到的第一个员工信息:" + first.get());}

运行结果:

查找到的第一个员工信息:User(id=BAT003, name=唐二鹏, age=32, department=研发部, salary=9900.0)

4.2.5 findAny - 查找操作(找任意一个)

findAny方法用于获取Stream中的某个元素的Optional,如果Stream为空,则返回一个空的Optional,顺序流中总是返回第一个元素。

    @Testpublic void findAny() {List<User> userList = Arrays.asList(new User("BAT006", "包雅欣", "财务部", 25, 6000),new User("BAT003", "唐二鹏", "研发部", 32, 9900),new User("BAT004", "王一林", "研发部", 30, 9000),new User("BAT005", "梁南生", "研发部", 27, 8000));Optional<User> userOptional = userList.stream().filter(p->p.getAge()<30).findAny();userOptional.ifPresent(user -> System.out.println("查找到的任意一个员工信息:" + user));}

运行结果:

查找到的任意一个员工信息:User(id=BAT006, name=包雅欣, age=25, department=财务部, salary=6000.0)

结语

  以上就是今天要讲的内容,主要介绍了Stream里一些常见的方法使用,平常还是需要多去看下API,加强练习,才能熟练,对我们后续写代码有极大的帮助。

Java8新特性:Stream详细使用

目录

    • 一、简介
    • 二、创建Stream的常用方法
      • 2.1 使用Stream中的静态方法:of()、iterate()、generate()
      • 2.2 使用Collection下的 stream() 和 parallelStream() 方法
      • 2.3 使用Arrays 中的 stream() 方法,将数组转成流
      • 2.4 使用BufferedReader.lines() 方法
    • 三、中间操作符(Intermediate operations)
      • 3.1 无状态(Stateless)
        • 3.1.1 filter - 过滤操作
        • 3.1.2 map - 映射、转换操作
        • 3.1.3 flatmap - 映射、转换操作
        • 3.1.4 peek - 挑出操作
      • 3.2 有状态(Stateful)
        • 3.2.1 distinct - 去重操作
        • 3.2.2 sorted - 自然排序
        • 3.2.3 sorted(Comparator com) - 指定排序
        • 3.2.4 limit - 限流操作
        • 3.2.5 skip - 跳过操作
    • 四、终结操作符(Terminal operations)
      • 4.1 非短路操作
        • 4.1.1 forEach - 遍历操作
        • 4.1.2 forEachOrdered - 遍历操作
        • 4.1.3 toArray - 数组操作
        • 4.1.4 reduce - 规约操作
        • 4.1.5 collect - 收集操作
        • 4.1.6 max - 最大值操作
        • 4.1.7 min - 最小值操作
        • 4.1.8 count - 统计操作
      • 4.2 短路操作(short-circuiting)
        • 4.2.1 anyMatch - 匹配操作(任意一个匹配)
        • 4.2.2 allMatch - 匹配操作(所有都匹配)
        • 4.2.3 noneMatch - 匹配操作(没有一个匹配)
        • 4.2.4 findFirst - 查找操作(找第一个)
        • 4.2.5 findAny - 查找操作(找任意一个)
    • 结语

一、简介

  Java 8 API 添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据,类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API 将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如查找,过滤, 排序,聚合等等操作。Stream API可以极大提高Java程序员的工作效率,让代码更简洁,干净。

  • Stream本身不会存储元素
  • Stream不会改变数据源对象,相反会返回产生一个持有结果的新Stream
  • Steam操作是延迟执行的,这意味着他们会等到需要结果的时候才执行

二、创建Stream的常用方法

2.1 使用Stream中的静态方法:of()、iterate()、generate()

    @Testpublic void stream(){//1.1传入可变参数,字符串,数字等Stream<String> stringStream = Stream.of("Alian", "boy", "cat", "papa");//1.2传入对象Stream<User> userStream = Stream.of(new User("BAT031", "胡一菲", "销售部", 28, 3500));//2.1generate方法参数为Function<T, T>函数型接口的子类,比如产生正奇数Stream<Integer> oddStream = Stream.iterate(1, (x) -> x + 2);oddStream.limit(5).forEach(System.out::println);//3.1generate方法参数为Supplier<T> 供给型接口,比如生成1-1000的随机数:(int) Math.round(Math.random() * (m - n) + n)Stream<Integer> generateStream = Stream.generate(() -> (int) Math.round(Math.random() * (1000 - 1) + 1));generateStream.limit(10).forEach(System.out::println);//打印10个随机数}

2.2 使用Collection下的 stream() 和 parallelStream() 方法

stream是顺序流,parallelStream是并行流。

    @Testpublic void streamAndParallelStream(){//初始化一个list列表List<String> fruitList = Arrays.asList("apple","banana","orange","watermelon","pear");//获取一个顺序流Stream<String> stream = fruitList.stream();System.out.println("--------获取顺序流的结果-----------");stream.forEach(System.out::println);//获取一个并行流Stream<String> parallel = fruitList.parallelStream();System.out.println("--------获取并行流的结果-----------");parallel.forEach(System.out::println);}

运行结果:

--------获取顺序流的结果-----------
apple
banana
orange
watermelon
pear
--------获取并行流的结果-----------
orange
watermelon
banana
apple
pear

2.3 使用Arrays 中的 stream() 方法,将数组转成流

    @Testpublic void arraysToStream(){//初始化一个String数组(当然也可以去其他类型的数组)String[] animal = new String[]{"cat","dog","pig","chicken","duck"};Stream<String> animalStream = Arrays.stream(animal);animalStream.forEach(System.out::println);}

运行结果:

cat
dog
pig
chicken
duck

2.4 使用BufferedReader.lines() 方法

    @Testpublic void readLineStream() throws FileNotFoundException {//通过BufferedReader获取到一个流(要自己写一个文件哦,比如我这里的"C:\\myStream.txt")BufferedReader bufReader = new BufferedReader(new FileReader("C:\\myStream.txt"));Stream<String> lineStream = bufReader.lines();lineStream.forEach(System.out::println);}

运行结果:

我在使用Java 8 Stream API进行测试(BufferedReader.lines()方式获取流)

三、中间操作符(Intermediate operations)

3.1 无状态(Stateless)

3.1.1 filter - 过滤操作

  filter方法对原Stream按照指定条件过滤,在新建的Stream中,只包含满足条件的元素,将不满足条件的元素过滤掉。

    @Testpublic void filter() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT001", "胡昊天", "销售部", 28, 3500),new User("BAT002", "王大锤", "销售部", 27, 3000),new User("BAT003", "唐二鹏", "研发部", 32, 9900),new User("BAT004", "王一林", "研发部", 30, 9000));//过滤出用户表中年龄大于28岁的员工List<User> collect = userList.stream().filter(f -> f.getAge() > 28).collect(Collectors.toList());System.out.println("年龄大于28岁的员工信息:" + collect);//过滤出用户表中年龄大于28岁并且工资大于9000元的员工List<User> collect2 = userList.stream().filter(f -> (f.getAge() > 28 && f.getSalary() > 9000)).collect(Collectors.toList());System.out.println("年龄大于28岁并且工资大于9000元的员工信息:" + collect2);}

运行结果:

年龄大于28岁的员工信息:[User(id=BAT003, name=唐二鹏, age=32, department=研发部, salary=9900.0), User(id=BAT004, name=王一林, age=30, department=研发部, salary=9000.0)]
年龄大于28岁并且工资大于9000元的员工信息:[User(id=BAT003, name=唐二鹏, age=32, department=研发部, salary=9900.0)]

3.1.2 map - 映射、转换操作

  map接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。map方法将对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。

    @Testpublic void map() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//获取列表中员工的姓名(新生成的Stream只包含转换生成的元素)List<String> collect = userList.stream().map(User::getName).collect(Collectors.toList());System.out.println("获取到的员工姓名:" + collect);//mapToDoubleSystem.out.println("员工的工资都转成double:");userList.stream().mapToDouble(User::getSalary).forEach(System.out::println);//mapToIntSystem.out.println("员工的年龄都转成int:");userList.stream().mapToInt(User::getAge).forEach(System.out::println);}

运行结果:

获取到的员工姓名:[梁南生, 包雅馨, 罗考聪]
员工的工资都转成double:
8000.0
6000.0
7400.0
员工的年龄都转成int:
27
25
35

3.1.3 flatmap - 映射、转换操作

  flatmap接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流。每个部分流中的每个值成单独小流,再串成一个整体流。即对Stream中的每一个元素通过转换函数转换,不同的是,该换转函数的对象是一个Stream,也不会再创建一个新的Stream,而是将原Stream的元素取代为转换的Stream

    @Testpublic void flatMap() {//flatmap接收的参数是一个StreamSystem.out.println("一、把流中的短横线替换后输出的结果:");Stream.of("A-l-i-a-n ","l-o-v-e ","C-S-D-N").flatMap(e->Stream.of(e.split("-"))).forEach(System.out::print);System.out.println();System.out.println("二、把流中的每个数据乘以10的结果:");Stream.of(2,5,8,9).flatMap(n->Stream.of(n*10)).forEach(System.out::println);}

运行结果:

一、把流中的短横线替换后输出的结果:
Alian love CSDN
二、把流中的每个数据乘以10的结果:
20
50
80
90

3.1.4 peek - 挑出操作

  peek方法和map一样能得到流中的每一个元素,只不过map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。peek方法会生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数,并且消费函数优先执行。

    @Testpublic void peek() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT008", "张伟杰", "测试部", 24, 7000),new User("BAT009", "胡俊伟", "研发部", 24, 4500));List<User> collect = userList.stream().peek(p -> p.setDepartment("运维部")).collect(Collectors.toList());System.out.println("部门都改为运维部:"+collect);}

运行结果:

部门都改为运维部后的信息:[User(id=BAT008, name=张伟杰, age=24, department=运维部, salary=7000.0), User(id=BAT009, name=胡俊伟, age=24, department=运维部, salary=4500.0)]

3.2 有状态(Stateful)

3.2.1 distinct - 去重操作

  distinct方法对原Stream中重复的元素进行剔除,生成的新Stream中没有没有重复的元素。

    @Testpublic void distinct() {System.out.println("按照类型去重结果:");Stream.of(3, 6, 9, 3, 9, 5).distinct().forEach(System.out::println);List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000));System.out.println("按照对象去重结果:");userList.stream().distinct().forEach(System.out::println);}

运行结果:

按照类型去重结果:
3
6
9
5
按照对象去重结果:
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)

3.2.2 sorted - 自然排序

sorted方法将对原Stream进行排序,返回一个有序的新Stream。

    @Testpublic void sorted() {//自然排序结果System.out.println("数字自然排序结果:");Stream.of(15, 28, 6, 9).sorted().forEach(System.out::println);System.out.println("字符自然排序结果:");Stream.of("b", "ab", "ba", "c").sorted().forEach(System.out::println);}

运行结果:

数字自然排序结果:
6
9
15
28
字符自然排序结果:
ab
b
ba
c

3.2.3 sorted(Comparator com) - 指定排序

sorted(Comparator)方法接收一个自定义排序规则函数(Comparator)。

    @Testpublic void sortedWithCompare() {List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//按照年龄升序排序System.out.println("按照年龄升序排序");userList.stream().sorted(Comparator.comparingInt(User::getAge)).forEach(System.out::println);//按照年龄倒序排序System.out.println("按照年龄倒序排序");userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).forEach(System.out::println);}

运行结果:

按照年龄升序排序
User(id=BAT012, name=张萌萌, age=20, department=行政部, salary=3500.0)
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)
按照年龄倒序排序
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)
User(id=BAT012, name=张萌萌, age=20, department=行政部, salary=3500.0)

3.2.4 limit - 限流操作

limit(n)方法限制从流中获得前n个数据。

    @Testpublic void limit() {List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//按照年龄倒序排序后取前面两条记录System.out.println("按照年龄倒序排序后取前面两条记录:");userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).limit(2).forEach(System.out::println);}

运行结果:

按照年龄倒序排序后取前面两条记录:
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)

3.2.5 skip - 跳过操作

skip(n)方法跳过n元素可以配合limit进行操作。

    @Testpublic void skip() {List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//按照年龄倒序排序后取前面两条记录System.out.println("按照年龄倒序排序后跳过一条数据取两条记录:");userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).skip(1).limit(2).forEach(System.out::println);}

运行结果:

按照年龄倒序排序后跳过一条数据取两条记录:
User(id=BAT010, name=胡健儿, age=23, department=人事部, salary=4000.0)
User(id=BAT012, name=张萌萌, age=20, department=行政部, salary=3500.0)

四、终结操作符(Terminal operations)

4.1 非短路操作

4.1.1 forEach - 遍历操作

forEach方法前面已经用了好多次,其用于遍历Stream中的所元素,顺序流下按照插入数据的顺序进行输出,并行流的时候是随机输出的。

    @Testpublic void forEach() {//初始化一个数据列表List<Integer> list = Arrays.asList(2, 3, 4, 5, 6);System.out.println("顺序流下输出:");list.stream().sorted().forEach(f -> System.out.println("forEach顺序流下数据:" + f));System.out.println("并行流下输出:");list.parallelStream().forEach(f -> System.out.println("forEach并行流下数据:" + f));List<User> userList = Arrays.asList(new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//按照年龄倒序排序后取前面两条记录System.out.println("跳过前面一条数据后输出:");userList.stream().skip(1).forEach(System.out::println);}

运行结果:

顺序流下输出:
forEach顺序流下数据:2
forEach顺序流下数据:3
forEach顺序流下数据:4
forEach顺序流下数据:5
forEach顺序流下数据:6
并行流下输出:
forEach并行流下数据:4
forEach并行流下数据:6
forEach并行流下数据:5
forEach并行流下数据:2
forEach并行流下数据:3
跳过前面一条数据后输出:
User(id=BAT011, name=陶建文, age=25, department=运维部, salary=8000.0)
User(id=BAT012, name=张萌萌, age=20, department=行政部, salary=3500.0)

4.1.2 forEachOrdered - 遍历操作

forEachOrdered方法与forEach类似,都是遍历Stream中的所有元素,不同的是,如果该Stream预先设定了顺序,会按照预先设定的顺序执行(Stream是无序的),默认为元素插入的顺序。顺序流下按照插入数据的顺序进行输出,并行流的时候流的遇到顺序得到保持。

    @Testpublic void forEachOrdered() {List<Integer> list = Arrays.asList(2, 3, 4, 5, 6, 7);System.out.println("forEachOrdered顺序流下输出:");list.parallelStream().forEachOrdered(f -> System.out.println("forEachOrdered顺序流下数据:" + f));System.out.println();System.out.println("forEachOrdered并行流下输出(流的遇到顺序得到保持):");list.parallelStream().forEachOrdered(f -> System.out.println("forEachOrdered并行流下数据:" + f));}

运行结果:

forEachOrdered顺序流下输出:
forEachOrdered顺序流下数据:2
forEachOrdered顺序流下数据:3
forEachOrdered顺序流下数据:4
forEachOrdered顺序流下数据:5
forEachOrdered顺序流下数据:6
forEachOrdered顺序流下数据:7forEachOrdered并行流下输出(流的遇到顺序得到保持):
forEachOrdered并行流下数据:2
forEachOrdered并行流下数据:3
forEachOrdered并行流下数据:4
forEachOrdered并行流下数据:5
forEachOrdered并行流下数据:6
forEachOrdered并行流下数据:7

4.1.3 toArray - 数组操作

toArray 转成数组,也可以提供自定义数组生成器

    @Testpublic void toArray() {Object[] animal= Stream.of("cat", "dog", "pig", "chicken", "duck").toArray();for(Object a:animal){System.out.println("数组里有:"+a);}}

运行结果:

数组里有:cat
数组里有:dog
数组里有:pig
数组里有:chicken
数组里有:duck

4.1.4 reduce - 规约操作

reduce方法是一个规约操作,所有的元素归约成一个。比如对所有元素求和,乘积等。这里实现了一个求和和乘积的方法,并指定了初始化的值分别为0和1(乘法指定1开始,不然没有意义).

    @Testpublic void reduce() {int sum = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).reduce(0, Integer::sum);System.out.println("1到10的和等于:" + sum);int product = Stream.of(1, 2, 3, 4, 5).reduce(1, (e1, e2) -> e1 * e2);System.out.println("1到5的乘积等于:" + product);}

运行结果:

1到10的和等于:55
1到5的乘积等于:120

4.1.5 collect - 收集操作

collect 操作我们也使用了很多次了,就不过多详细介绍了

@Testpublic void collect() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT004", "王一林", "研发部", 30, 9000),new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//按年龄排序后转为listSystem.out.println("----------转list后的结果----------");userList.stream().sorted(Comparator.comparingInt(User::getAge)).collect(Collectors.toList()).forEach(System.out::println);//按工资排序后转为setSystem.out.println("----------转set后的结果----------");userList.stream().sorted(Comparator.comparingDouble(User::getSalary)).collect(Collectors.toCollection(LinkedHashSet::new)).forEach(System.out::println);//以员工的编号做为key,员工信息作为value转换为mapSystem.out.println("----------以员工的编号做为key,员工信息作为value转换为map----------");Map<String, User> collect = userList.stream().collect(Collectors.toMap(User::getId, u -> u));collect.forEach((x, y) -> System.out.println(x + "->" + y));//把名字用逗号分隔System.out.println("----------名字拼接后结果----------");String nameStr = userList.stream().map(User::getName).collect(Collectors.joining(","));System.out.println(nameStr);System.out.println("----------按部门分组统计----------");//按部门进行分组统计人数Map<String, Long> groupingBy = userList.stream().collect(Collectors.groupingBy(User::getDepartment, Collectors.counting()));groupingBy.forEach((x, y) -> System.out.println(x + "->" + y));//获取工资汇总信息System.out.println("----------工资汇总信息----------");DoubleSummaryStatistics statistics = userList.stream().collect(Collectors.summarizingDouble(User::getSalary));System.out.println("最高工资:" + statistics.getMax());System.out.println("最低工资:" + statistics.getMin());System.out.println("工资总和:" + statistics.getSum());System.out.println("平局工资:" + statistics.getAverage());System.out.println("总记录数:" + statistics.getCount());}

运行结果:

----------转list后的结果----------
User(id=BAT006, name=包雅馨, age=25, department=财务部, salary=6000.0)
User(id=BAT005, name=梁南生, age=27, department=研发部, salary=8000.0)
User(id=BAT004, name=王一林, age=30, department=研发部, salary=9000.0)
User(id=BAT007, name=罗考聪, age=35, department=测试部, salary=7400.0)
----------转set后的结果----------
User(id=BAT006, name=包雅馨, age=25, department=财务部, salary=6000.0)
User(id=BAT007, name=罗考聪, age=35, department=测试部, salary=7400.0)
User(id=BAT005, name=梁南生, age=27, department=研发部, salary=8000.0)
User(id=BAT004, name=王一林, age=30, department=研发部, salary=9000.0)
----------以员工的编号做为key,员工信息作为value转换为map----------
BAT004->User(id=BAT004, name=王一林, age=30, department=研发部, salary=9000.0)
BAT007->User(id=BAT007, name=罗考聪, age=35, department=测试部, salary=7400.0)
BAT005->User(id=BAT005, name=梁南生, age=27, department=研发部, salary=8000.0)
BAT006->User(id=BAT006, name=包雅馨, age=25, department=财务部, salary=6000.0)
----------名字拼接后结果----------
王一林,梁南生,包雅馨,罗考聪
----------按部门分组统计----------
测试部->1
财务部->1
研发部->2
----------工资汇总信息----------
最高工资:9000.0
最低工资:6000.0
工资总和:30400.0
平局工资:7600.0
总记录数:4

4.1.6 max - 最大值操作

max方法根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最大的元素。

    @Testpublic void max() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//筛选出年龄最大的员工信息Optional<User> userOptional = userList.stream().max(Comparator.comparingInt(User::getAge));//只是演示此处不做判断了User user = userOptional.get();System.out.println("年龄最大的员工信息:" + user);}

运行结果:

年龄最大的员工信息:User(id=BAT007, name=罗考聪, age=35, department=测试部, salary=7400.0)

4.1.7 min - 最小值操作

min方法根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最小的元素。

    @Testpublic void min() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//筛选出工资最低的员工信息Optional<User> userOptional = userList.stream().min(Comparator.comparingDouble(User::getSalary));//只是演示此处不做判断了User user = userOptional.get();System.out.println("工资最低的员工信息:" + user);}

运行结果:

工资最低的员工信息:User(id=BAT006, name=包雅馨, age=25, department=财务部, salary=6000.0)

4.1.8 count - 统计操作

count方法将返回Stream中元素的个数,一般用于流中间操作后的统计。

    @Testpublic void count() {//初始化一个用户列表List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅馨", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400.0));//统计年龄小于30的员工的个数long count = userList.stream().filter(f -> f.getAge() < 30).count();System.out.println("年龄小于30的员工的个数:" + count);}

运行结果:

年龄小于30的员工的个数:2	

4.2 短路操作(short-circuiting)

4.2.1 anyMatch - 匹配操作(任意一个匹配)

anyMatch方法按照指定的条件匹配到Stream中任意一个元素则返回true,否则返回false。

    @Testpublic void anyMatch() {List<User> userList = Arrays.asList(new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包三雅", "财务部", 25, 6000),new User("BAT007", "罗考聪", "测试部", 35, 7400),new User("BAT008", "张伟杰", "测试部", 24, 7000));//匹配任意一个年龄大于35岁的员工boolean b = userList.stream().anyMatch(p -> p.getAge() > 35);System.out.println("匹配任意一个年龄大于34岁的员工:" + b);//匹配任意一个“张”姓的员工boolean flag = userList.stream().anyMatch(p -> p.getName().startsWith("张"));System.out.println("匹配任意一个“张”姓的员工:" + flag);}

运行结果:

匹配任意一个年龄大于34岁的员工:false
匹配任意一个“张”姓的员工:true

4.2.2 allMatch - 匹配操作(所有都匹配)

allMatch方法按照指定的条件匹配Stream中所有的元素才返回true,否则返回false。

    @Testpublic void allMatch() {List<User> userList = Arrays.asList(new User("BAT009", "胡俊伟", "研发部", 24, 4500),new User("BAT010", "胡健儿", "人事部", 23, 4000),new User("BAT011", "陶建文", "运维部", 25, 8000),new User("BAT012", "张萌萌", "行政部", 20, 3500));//匹配所有人年龄都大于22岁boolean b = userList.stream().allMatch(p -> p.getAge() > 22);System.out.println("所有人年龄都大于22岁:" + b);//匹配所有人年龄都大于18岁boolean flag = userList.stream().allMatch(p -> p.getAge() > 18);System.out.println("所有人年龄都大于18岁:" + flag);}

运行结果:

所有人年龄都大于22岁:false
所有人年龄都大于18岁:true

4.2.3 noneMatch - 匹配操作(没有一个匹配)

noneMatch方法按照指定的条件,Stream中没有一个元素匹配得上才返回true,否则返回false。

    @Testpublic void noneMatch() {List<User> userList = Arrays.asList(new User("BAT001", "胡昊天", "销售部", 28, 3500),new User("BAT002", "王大锤", "销售部", 27, 3000),new User("BAT003", "唐二鹏", "研发部", 32, 9900),new User("BAT004", "王一林", "研发部", 30, 9000),new User("BAT005", "梁南生", "研发部", 27, 8000));//匹配没有一个“李”姓员工boolean b = userList.stream().noneMatch(p -> p.getName().startsWith("李"));System.out.println("没有一个李姓员工:" + b);//匹配没有一个“胡”姓员工boolean flag = userList.stream().noneMatch(p -> p.getName().startsWith("胡"));System.out.println("没有一个胡姓员工:" + flag);}

运行结果:

没有一个李姓员工:true
没有一个胡姓员工:false

4.2.4 findFirst - 查找操作(找第一个)

findFirst方法用于获取Stream中的第一个元素的Optional,如果Stream为空,则返回一个空的Optional。

    @Testpublic void findFirst() {List<User> userList = Arrays.asList(new User("BAT003", "唐二鹏", "研发部", 32, 9900),new User("BAT004", "王一林", "研发部", 30, 9000),new User("BAT005", "梁南生", "研发部", 27, 8000),new User("BAT006", "包雅欣", "财务部", 25, 6000));Optional<User> first = userList.stream().findFirst();System.out.println("查找到的第一个员工信息:" + first.get());}

运行结果:

查找到的第一个员工信息:User(id=BAT003, name=唐二鹏, age=32, department=研发部, salary=9900.0)

4.2.5 findAny - 查找操作(找任意一个)

findAny方法用于获取Stream中的某个元素的Optional,如果Stream为空,则返回一个空的Optional,顺序流中总是返回第一个元素。

    @Testpublic void findAny() {List<User> userList = Arrays.asList(new User("BAT006", "包雅欣", "财务部", 25, 6000),new User("BAT003", "唐二鹏", "研发部", 32, 9900),new User("BAT004", "王一林", "研发部", 30, 9000),new User("BAT005", "梁南生", "研发部", 27, 8000));Optional<User> userOptional = userList.stream().filter(p->p.getAge()<30).findAny();userOptional.ifPresent(user -> System.out.println("查找到的任意一个员工信息:" + user));}

运行结果:

查找到的任意一个员工信息:User(id=BAT006, name=包雅欣, age=25, department=财务部, salary=6000.0)

结语

  以上就是今天要讲的内容,主要介绍了Stream里一些常见的方法使用,平常还是需要多去看下API,加强练习,才能熟练,对我们后续写代码有极大的帮助。

11136

与本文相关的文章

发布评论

评论列表 (0)

  1. 暂无评论