JAVA8新特性Stream

实现前端实现多国语言切换 = 实现前端页面的资源国际化,需要依赖jQuery.i18n.properties插件[TOC]

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 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, 需要得到先前访问的元素的状态。

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

常用的中间操作说明
状态 函数 作用
AAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
无状态 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"));

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

常用的终端操作说明
函数 作用
AAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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探秘

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

你可能感兴趣的:(JAVA8新特性Stream)