Java8中的Stream详解

目录

一.什么是Stream

1.Stream的特征

2.Stream的原理

3.Stream和Collections的区别

4.Stream的操作

5.不使用Stream和使用Stream对比

 二.常见应用场景

1.生成流

 2.forEach

3.map

4.filter

5.limit

6.sorted

7.Collectors

8.统计


一.什么是Stream

Stream是Java8提供了一种高效且易于使用的处理数据的方式,类似于数据库查询语句,可以理解为遍历数据集的高级迭代器。要处理集合看作一种流, 在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。集合是数据,流就是处理中的数据,也是一种计算方式。

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

1.Stream的特征

Stream(流)是一个来自数据源的元素队列并支持聚合操作。

  1. 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  2. 数据源 流的来源:可以是集合,数组,I/O channel, 产生器generator 等。
  3. 聚合操作:类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
  4. Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  5. 内部迭代:以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

2.Stream的原理

https://blog.csdn.net/lcgoing/article/details/87918010

3.Stream和Collections的区别

  1. 无存储stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。

  2. 为函数式编程而生。对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream

  3. 惰式执行stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。

  4. 可消费性stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。

4.Stream的操作

  1. 中间操作(intermediate operations):一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
  2. 结束操作(terminal operations):一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
  3. 中间操作总是会惰式执行,调用中间操作只会生成一个标记了该操作的新stream,仅此而已。
  4. 结束操作会触发实际计算,计算发生时会把所有中间操作积攒的操作以pipeline的方式执行,这样可以减少迭代次数。计算完成之后stream就会失效。
  5. short-circuiting操作:对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。当操作一个无限大的 Stream,而又希望在有限时间内完成操作,则在管道内拥有一个 short-circuiting 操作是必要非充分条件。

常用API:

  • Intermediate:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered。
  • Terminal:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator。
  • Short-circuiting:anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit。

5.不使用Stream和使用Stream对比

不使用Stream:

package Lambda;


import java.util.*;

public class Liu {

    public static final void main(String[] s) {
        List<Student> students = new ArrayList<>(Arrays.asList(new Student(2, "好"),
                new Student(3, "坏"),new Student(4, "好"),new Student(1, "好")));
        List<Student> newStudents = new ArrayList<>();
        //选择特定元素,放进newStudents里
        for(Student t: students){
            if(t.getType() == Student.STU_TYPE){
                newStudents.add(t);
            }
        }
        //根据idnewStudents将排序
        Collections.sort(newStudents, new Comparator<Student>(){
            @Override
            public int compare(Student t1, Student t2){
                return t2.getId().compareTo(t1.getId());
            }
        });
        //把经过排序的集合newStudents的ids提取出来,放进studentIds里
        List<Integer> studentIds = new ArrayList<>();
        for(Student t: newStudents){
            studentIds.add(t.getId());
        }
        //打印
        System.out.println(studentIds);

    }

    /**
     * 学生类
     */
    static class Student {
        private static final String STU_TYPE = "好";
        private Integer id;
        private String type;

        public Student(Integer id, String type) {
            this.id = id;
            this.type = type;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
    }
}

使用Stream:

package Lambda;


import java.util.*;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

public class Liu {

    public static final void main(String[] s) {
        List<Student> students = new ArrayList<>(Arrays.asList(new Student(2, "好"),
                new Student(3, "坏"),new Student(4, "好"),new Student(1, "好")));
        List<Student> newStudents = new ArrayList<>();
        // 选择特定元素 -> 排序 -> 取值
        List<Integer> studentIds = students.parallelStream().
                filter(t -> t.getType() == Student.STU_TYPE).
                sorted(comparing(Student::getType).reversed()).
                map(Student::getId).
                collect(toList());
        //打印
        System.out.println(studentIds);

    }

    /**
     * 学生类
     */
    static class Student {
        private static final String STU_TYPE = "好";
        private Integer id;
        private String type;

        public Student(Integer id, String type) {
            this.id = id;
            this.type = type;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
    }
}

 二.常见应用场景

1.生成流

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

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

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

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

 2.forEach

Stream 提供了新的方法 'forEach' 来迭代流中的每个数据。

// 使用Stream.forEach()进行迭代
Stream<String> stream = Stream.of("I", "love", "you", "too");
stream.forEach(str -> System.out.println(str));

3.map

map 方法用于映射每个元素到对应的结果。

//获取对应的平方数
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream().map(i -> i*i).distinct().collect(Collectors.toList());

4.filter

filter 方法用于通过设置的条件过滤出元素。

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

5.limit

limit 方法用于获取指定数量的流。 

//输出10个随机数
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

6.sorted

sorted 方法用于对流进行排序。

//对10个随机数进行排序
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

7.Collectors

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

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
 
System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);

8.统计

一些产生统计结果的收集器也非常有用。它们主要用于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());

学习参考:

http://www.runoob.com/java/java8-streams.html

http://www.cnblogs.com/CarpenterLee/p/6545321.html

https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值