Java 8 之Stream

目录

 

一、什么是 Stream?

二、几个主要机制

1、生成流   filter

2、forEach   limit

3、map  sorted

4、并行(parallel)  count

5、Collectors

6、统计

三、操作案例

扫描二维码关注公众号,回复: 8633030 查看本文章

1、常用stream方式

2、中间件案例


一、什么是 Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作。可供流式操作的数据视图,类似数据库中视图的概念,它不改变源数据集合,如果对其进行改变的操作它会返回一个新的数据集合。

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

以上的流程转换为 Java 代码为:

List<Integer> transactionsIds = 
widgets.stream()
             .filter(b -> b.getColor() == RED)
             .sorted((x,y) -> x.getWeight() - y.getWeight())
             .mapToInt(Widget::getWeight)
             .sum();

二、几个主要机制

1、生成流   filter

在 Java 8 中, 集合接口有两个方法来生成流:

  • stream() − 为集合创建串行流。

  • parallelStream() − 为集合创建并行流。

filter 用于过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

2、forEach   limit

Stream 提供了新的方法 'forEach' 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:

limit   用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 / 5 条数据:

Random random = new Random(); 
random.ints().limit(10).forEach(System.out::println);
random.ints().limit(5).forEach(x -> System.out.println(x));

3、map  sorted

map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

sorted  排序

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数 map( i -> i*i) i表示每个元素 map类似于mapreduce阶段map distinct去重
List<Integer> squaresList = numbers.stream().map( i -> i*i).sorted().distinct().collect(Collectors.toList());
squaresList.forEach(System.out::println);
    

4、并行(parallel)  count

parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
int count = strings.parallelStream().filter(string -> string.isEmpty()).count();

5、Collectors

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
//Collectors.toList()  输出为一个list
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
//Collectors.joining(", ") 将元素合并,以,隔开
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
  

6、统计

另一些统计结果的收集器也非常有用。主要用于int、double、long等基本类型上,可以用来产生类似如下的统计结果。

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
 
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
 
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());

常用中间件
filter:过滤流,过滤流中的元素,返回一个符合条件的Stream
map:转换流,将一种类型的流转换为另外一种流。(mapToInt、mapToLong、mapToDouble 返回int、long、double基本类型对应的Stream)
flatMap:简单的说,就是一个或多个流合并成一个新流。(flatMapToInt、flatMapToLong、flatMapToDouble 返回对应的IntStream、LongStream、DoubleStream流。)
distinct:返回去重的Stream。
sorted:返回一个排序的Stream。
peek:主要用来查看流中元素的数据状态。
limit:返回前n个元素数据组成的Stream。属于短路操作
skip:返回第n个元素后面数据组成的Stream。

结束操作
forEach: 循环操作Stream中数据。
toArray: 返回流中元素对应的数组对象。
reduce: 聚合操作,用来做统计。
collect: 聚合操作,封装目标数据。
min、max、count: 聚合操作,最小值,最大值,总数量。
anyMatch: 短路操作,有一个符合条件返回true。
allMatch: 所有数据都符合条件返回true。
noneMatch: 所有数据都不符合条件返回true。
findFirst: 短路操作,获取第一个元素。
findAny: 短路操作,获取任一元素。
forEachOrdered: 暗元素顺序执行循环操作。

三、操作案例

1、常用stream方式

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

List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

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

Integer[] nums = new Integer[10];
Stream<Integer> stream = Arrays.stream(nums);

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

Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
 
Stream<Integer> stream2 = Stream.iterate(10, (x) -> x + 2).limit(6);
stream2.forEach(System.out::println); // 0 2 4 6 8 10  从10开始递加2,共6个

Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
stream3.forEach(System.out::println);

(4)使用 BufferedReader.lines() 方法,将每行内容转成流

BufferedReader reader = new BufferedReader(new FileReader("F:\\test_stream.txt"));
Stream<String> lineStream = reader.lines();
lineStream.forEach(System.out::println);

2、中间件案例

import com.xin.Person;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Demo2 {
    public static void main(String[] args) {
        List<Person> persionList = new ArrayList<Person>();
        persionList.add(new Person(1,"张三","男",38));
        persionList.add(new Person(2,"小小","女",2));
        persionList.add(new Person(3,"李四","男",65));
        persionList.add(new Person(4,"王五","女",20));
        persionList.add(new Person(5,"赵六","男",38));
        persionList.add(new Person(6,"大大","男",65));

        //1、只取出该集合中所有姓名组成一个新集合
        List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList());
        nameList.forEach(System.out::println);

//        2、只取出该集合中所有id组成一个新集合    boxed:数值流转换为流   mapToInt(T -> int) : return IntStream
        List<Integer> idList=persionList.stream().mapToInt(Person::getId).boxed().collect(Collectors.toList());
        List<Integer> idList2=persionList.stream().map(Person::getId).collect(Collectors.toList());
        System.out.println(idList.toString());

        //3、list转map,key值为id,value为Person对象-->Person:Person or person:peron  p大小写都行
        Map<Integer, Person> personmap = persionList.stream().collect(Collectors.toMap(Person::getId,Person -> Person));
        System.out.println(personmap.toString());

        //4、list转map,key值为id,value为name
        Map<Integer, String> namemap = persionList.stream().collect(Collectors.toMap(Person::getId, Person::getName));
        System.out.println(namemap.toString());

        //5、进行map集合存放,key为age值 value为Person对象 它会把相同age的对象放到一个集合中
        Map<Integer, List<Person>> ageMap = persionList.stream().collect(Collectors.groupingBy(Person::getAge));
        System.out.println(ageMap.toString());

        //6、获取最小年龄
        Integer ageMin = persionList.stream().mapToInt(Person::getAge).min().getAsInt();
        System.out.println("最小年龄为: "+ageMin);

        //7、获取最大年龄
        Integer ageMax = persionList.stream().mapToInt(Person::getAge).max().getAsInt();
        System.out.println("最大年龄为: "+ageMax);

        //8、集合年龄属性求和
        Integer ageAmount = persionList.stream().mapToInt(Person::getAge).sum();
        System.out.println("年龄总和为: "+ageAmount);
    }
}

filter案例

        //9.求年纪大于20岁的人数   p -> p.getAge()
        long count = persionList.stream().filter(person -> person.getAge() > 20).count();
        System.out.println(count);

        //10、求年纪大于20岁、性别为男的人数   p -> p.getGender()必须放在前面
        long count1 = persionList.stream().filter(p -> p.getAge() > 20).filter(p -> p.getGender().equals("男")).count();
        System.out.println(count1);

sorted案例

一、数组
//11、sorted相关例子
        String[] arr={"scsa","bi","a","cd","ca156165"};
        //按照字典姓名排序
        Object[] objects = Arrays.stream(arr).sorted((String o1, String o2) -> o1.length() - o2.length()).toArray();
        Object[] objects1 = Arrays.stream(arr).sorted().toArray();
        //姓名长度排序
        Object[] objects2 = Arrays.stream(arr).sorted(Comparator.comparing(String::length)).toArray();
        /**
         * 倒序
         * reversed(),java8泛型推导的问题,所以如果comparing里面是非方法引用的lambda表达式就没办法直接使用reversed()
         * Comparator.reverseOrder():也是用于翻转顺序,用于比较对象(Stream里面的类型必须是可比较的)
         * Comparator. naturalOrder():返回一个自然排序比较器,用于比较对象(Stream里面的类型必须是可比较的)
         * */
        Object[] objects3 = Arrays.stream(arr).sorted(Comparator.comparing(String::length).reversed()).toArray();
        for(Object ob:objects){
            System.out.println(ob);
        }
        Arrays.stream(arr).sorted(Comparator.reverseOrder()).forEach(System.out::println);
        //输出:bc、abcd、abc、a
        Arrays.stream(arr).sorted(Comparator.naturalOrder()).forEach(System.out::println);
        //输出:a、abc、abcd、b

        //先按照首字母排序,之后按照String的长度排序  com1 自定义静态方法
        Arrays.stream(arr).sorted(Comparator.comparing(Demo2::com1).thenComparing(String::length)).forEach(System.out::println);
        //输出:a、abc、abcd、bc
    }
    public static char com1(String x){
        return x.charAt(0);
    }

二、集合
 //1、找到年龄最小的岁数
        Collections.sort(persionList, (x, y) -> x.getAge()-(y.getAge()));
        Integer age = persionList.get(0).getAge();
        System.out.println("年龄最小的有:" + age);
        //输出:年龄最小的有:2

        //2、找到年龄最小的姓名
        String name = persionList.stream()
                .sorted(Comparator.comparingInt(x -> x.getAge()))
                .findFirst()   //取第一个数据
                .get().getName();
        System.out.println("年龄最小的姓名:" + name);
        //输出:年龄最小的姓名:小小

map和flatmap区别

package com;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;



import java.util.function.Function;

public class Demo4 {
        public static void main(String[] args) throws IOException {
//      要求:将list最后输出 abc123 or a b c 1 2 3 即各单位独立,而不是abc一组,123一组
//      map是输出多个流,flatmap是将多个流输出成一个流
            List<String> list = Arrays.asList("a,b,c", "1,2,3");
            Stream<String> stream = list.stream();

            //objectStream中含有6个元素,因为flagmap压平
            Stream<Object> objectStream = stream.flatMap(new Function<String, Stream<?>>() {
                @Override
                public Stream<?> apply(String s) {
                    //1去逗号   2、转成Stream
//                    String[] split = s.split(",");
                    String[] split = s.split(",");
//                    String s1 = s.replaceAll(",", "");
//                Stream<String> split1 = Stream.of(split);
                    Stream<String> stream1 = Arrays.stream(split);
                    return stream1;
                }
            });
            List<Object> collect = objectStream.collect(Collectors.toList());
            System.out.println(objectStream.count());         
            System.out.println(collect.size());
            collect.forEach(System.out::print);

            System.out.println();
            System.out.println("------------------");
            //stringStream中含有2个元素,因为list集合有两个元素,map不具备压平机制
            Stream<String> stringStream = list.stream().map(new Function<String, String>() {

                @Override
                public String apply(String s) {
                    StringBuffer sb = new StringBuffer();
                    String[] split = s.split(",");
                    for (String s1 : split) {
                        sb.append(s1);
                    }
                    return sb.toString();
                }
            });

            List<String> collect2 = stringStream.collect(Collectors.toList());
            System.out.println(collect2.size());
            collect2.forEach(System.out::print);

            System.out.println();
            System.out.println("------------------");
            //将map输出集合中两个数组,分别转换流再转换成数组遍历输出
            List<String[]> collect1 = list.stream().map(p -> p.split(",")).collect(Collectors.toList());
            System.out.println(collect1.size());
            collect1.forEach(s -> Arrays.stream(s).collect(Collectors.toList()).forEach(System.out::print));
        }
}
发布了77 篇原创文章 · 获赞 19 · 访问量 4065

猜你喜欢

转载自blog.csdn.net/qq_41861558/article/details/103072288