JAVA8新特性Stream

3 篇文章 0 订阅

Stream 简单介绍

java8中引入了一个新的特性Stream(流)
官方介绍:A sequence of elements supporting sequential and parallel aggregate operations.(支持顺序和并行聚合操作的一系列元素)
聚合:在信息科学中是指对有关的数据进行内容挑选、分析、归类,最后分析得到人们想要的结果(百度百科)

1、如何产生一个Stream

    @Test
    public void createStream() {
        Collection list = new ArrayList();
        Map map = new HashMap();
        Object[] intArray = {1,2,3,4,5};

        //集合产生流
        Stream listStream = list.stream();
        Stream listParallelStream = list.parallelStream();

        //数组产生流
        Stream mapStream = Arrays.stream(intArray);

        File file = new File("stream.txt");
        try {
            BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
            //从文件读取数据形成流
            Stream<String> lineStream = bufferedReader.lines();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

2、Stream的操作

Stream的操作分为两大类,一类是 中间操作 ,不会立即执行,只是返回一个新的Stream,这个新的Stream记录了上一步的操作。另一类是 终端操作 ,最终操作会使用Stream,真正的执行之前的中间操作,并且完成终端里的具体操作。(比如将结果封装到一个List里面)

2.1、中间操作(Intermediate operations)
//无状态的操作
list.stream().filter(Objects::nonNull).map(String::toLowerCase).forEach(System.out::println);
//有状态的操作
list.stream().distinct().sorted().forEach(System.out::println);

上面的 filter,map 都是中间操作。filter 表示过滤掉为null的值,map 表示将string装化为小写字母,它们都接受一个Lambda

无状态的操作, 像filter,map都是无状态的操作, 处理一个新的元素时不需要获得先前遍历过的元素的状态。

有状态的操作,像distinct, sorted, 需要得到先前访问的元素的状态。

有状态的操作在产生结果前需要获得完整的输入。 因此有状态的操作一个并行流时, 可能需要多次传入数据或者需要缓存数据。 而无状态的操作只需传入一次数据。 所以并行流处理有状态的操作时可能比序列化流使用更多的时间

常用的中间操作说明
状态函数作用
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
无状态filter(Predicate p)接收Lambda,从流中排除某些元素
无状态limit(long maxSize)截断流,使其元素不超过给定数量
无状态skip(long n)跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
无状态map(Function f)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
无状态flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
有状态sorted(Conparator comp)产生一个新流,其中按照比较器顺序排序
有状态sorted()产生一个新流,其中按自然顺序排序
有状态distinct()筛选,通过流所生成元素的hashCode()和equals()去除重复的元素
2.2、终端操作(Terminal operations)
//打印出不为null的,大写字母的小写
list.stream().filter(Objects::nonNull).map(String::toLowerCase).forEach(System.out::println);
//将不为Null的小写字母封装进一个map
List resultList = list.stream().filter(Objects::nonNull).map(String::toLowerCase).collect(Collectors.toList());
//根据list中的数据,过滤后是否有元素匹配"a",如果有返回true,没有返回false
boolean b = list.stream().filter(Objects::nonNull).map(String::toLowerCase).anyMatch(s -> s.equals("a"));

终端操作又可以分为短路非短路操作,这个应该很好理解,前者是指遇到某些符合条件的元素就可以得到最终结果;而后者是指必须处理所有元素才能得到最终结果。

常用的终端操作说明
函数作用
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素的总数
max(Comparator c)返回流中的最大值
min(Comparator c)返回流中的最小值
reduce(BinaryOperator b)返回值是Optional封装的对象
reduce(T identity, BinaryOperator b)可以将流中元素结合起来,得到一个值。默认返回 identity
collect(Collector collector)将数据源经过过滤、筛选等操作收集到对应的集合或者Map,或者收集他们的统计信息,如求和、平均值、最大值、最小值、记录数等
2.3、Stream的特点
  • 不存储数据:流不是一个存储元素的数据结构。 它只是传递源(source)的数据。
  • 功能性的(Functional in nature)。 在流上操作只是产生一个结果,不会修改源。 例如filter只是生成一个筛选后的stream,不会删除源里的元素。
  • 延迟搜索。 许多流操作, 如filter, map等,都是延迟执行。 中间操作总是lazy的。
  • Stream可能是无界的。 而集合总是有界的(元素数量是有限大小)。 短路操作如limit(n) , findFirst()可以在有限的时间内完成在无界的stream
  • 消费品。流的元素在流的声明周期内只能访问一次。 再次访问只能再重新从源中生成一个Stream

3、使用流的好处

  • 代码编写简洁
  • 集合操作很方便
  • 并发处理,使用 Fork/Join 模式(注意,一些有状态的中间操作使用并发处理会更慢)
    @Before
    public void init() {
        Random random = new Random();
        list = Stream.generate(() -> random.nextInt(100)).limit(100000000).collect(toList());
    }

    /**
     * 测试并行流
     */
    @Test
    public void testParallel() {
        long begin1 = System.currentTimeMillis();
        long num_1 = list.stream().filter(x->(x > 10)).count();
        long end1 = System.currentTimeMillis();
        System.out.println(num_1);
        System.out.println("未使用并行流:" + (end1-begin1));
        long num_2 = list.stream().parallel().filter(x->(x > 10)).count();
        long end2 = System.currentTimeMillis();
        System.out.println(num_2);
        System.out.println("使用并行流:" + (end2-end1));
    }
    //测试结果:
    //89001550
	//未使用并行流:412
	//89001550
	//使用并行流:125

参考博客
Java8 Stream原理深度解析
Java 8 Stream探秘

我的个人博客,有空来坐坐

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值