Java-8-流(1)

本文介绍了Java 8中的流(Stream)特性,重点讲解了外部迭代与内部迭代的区别,以及内部迭代的优势。通过实例展示了如何使用Stream进行过滤、计数等操作,并探讨了Stream的构造、转换及其常用操作,如collect方法的各种应用场景,如转换成集合、分组、计算等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java-8-流(1)

外部迭代与内部迭代

Java 程序员在使用集合类时,一个通用的模式是在集合上进行迭代,然后处理返回的每一
个元素

在数字集合里面统计大于100的数有几个

  public static void main(String[] args) {

        List<Integer> data = Number_Data.createData();

        int count = 0;

        for (Integer integer : data){

            if (integer > 100){
                count++;
            }
        }

        System.out.println(count);
    }

尽管这样的操作可行,但存在几个问题。每次迭代集合类时,都需要写很多样板代码。将for 循环改造成并行方式运行也很麻烦,需要修改每个 for 循环才能实现

for 循环的样板代码模糊了代码的本意,程序员必须阅读整个循环体才能理解。若是单一的 for 循环,倒也问题不大,但面对一个满是循环(尤其是嵌套循环)的庞大代码库时,负担就重了

for 循环其实是一个封装了迭代的语法糖看看它的工作原理。首先调用 iterator 方法,产生一个新的 Iterator 对象,进而控制整个迭代过程,这就是外部迭代。迭代过程通过显式调用 Iterator 对象的 hasNext 和 next方法完成迭代

使用迭代器在数字集合里面统计大于100的数有几个


        int num = 0;

        Iterator<Integer> integerIterator = data.iterator();

        while (integerIterator.hasNext()){

            if (integerIterator.next() > 100){
                num++;
            }

        }

        System.out.println(num);

简单理解外部迭代就是由用户来决定”做什么“和”怎么做“的操作

另一种方法就是内部迭代

使用内部迭在数字集合里面统计大于100的数有几个


   List<Integer> data = Number_Data.createData();

        long count = data.stream()
                .filter(integer -> integer > 100)
                .count();

        System.out.println(count);

每种操作都对应 Stream 接口的一个方法。为了找出来大于100的数有几个,需要对 Stream 对象进行过滤: filter 。过滤在这里是指“只保留通过某项测试的对象”。测试由一个函数完成,根据数字是否大于100,该函数返回 true 或者 false 。由于 Stream API 的函数式编程风格,我们并没有改变集合的内容,而是描述出 Stream 里的内容。 count() 方法计算给定 Stream 里包含多少个对象

内部迭代我们只需要提供”做什么“,把”怎么做“的任务交给了 JVM

使用内部迭代可以带来的好处:

  • 用户只需要关注问题,无需关注如何解决问题的细节

  • 使得 JVM可以利用短路、并行等对性能的提升变成可能

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)实现。

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

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

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

流的操作类型
  • Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历

  • Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。

在对于一个 Stream 进行多次转换操作 (Intermediate 操作),每次都对 Stream 的每个元素进行转换,而且是执行多次,这样时间复杂度就是 N(转换次数)个 for 循环里把所有操作都做掉的总和吗?

其实不是这样的,转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在 Terminal 操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。

流的构造与转换

public class M3 {


    public static void main(String[] args) {

        Stream stream1;

        Stream stream2;

        Stream stream3;
        //由单独的值构成
        Stream<String> stringStream = Stream.of("sjd","kjfu","4545");

        //由数组构成
        String[] strings = new String[]{"a","ab","abc"};

        stream1 = Stream.of(strings);

        stream2 = Arrays.stream(strings);

//        //由集合构成,最常用了
        List<String> list = Arrays.asList(strings);

        stream3 = list.stream();

//对于基本数值型,目前有三种对应的包装类型的Stream:IntStream、LongStream、DoubleStream
        IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
        System.out.println("========================================");
        IntStream.range(1, 3).forEach(System.out::println);
        System.out.println("========================================");
        IntStream.rangeClosed(1, 3).forEach(System.out::println);



    }
}


自己构造流
Stream.generate

Stream.generate通过实现 Supplier 接口,你可以自己来控制流的生成


 public static void main(String[] args) {


        //		//生成100以内的30个随机整数,用来构造测试随机数不失为一种简便的方式
        Stream.generate(() ->
                new Random().nextInt(100))
                .limit(30).forEach(System.out::println);


        System.out.println("=================================");
        IntStream.generate(() ->
                (int) (System.nanoTime() % 100)).limit(20).forEach(System.out::println);



        System.out.println("=================================");

//                //random其实提供了更方便的ints()方法
        new Random().ints().limit(10).forEach(System.out::println);
    }

Stream.generate() 还接受自己实现的 Supplier。例如在构造海量测试数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值