java8新特性:三,Stream

java8新特性:三,Stream

1 Stream介绍

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

±-------------------+ ±-----+ ±-----+ ±–+ ±------+
| 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();

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可以由数组或集合创建,对流的操作分为两种:

1.中间操作:每次返回一个新的流,可以有多个。
2.终端操作:每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。

Stream有以下几个特性:

1.stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
2.stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
3.stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。

3.生成流

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

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

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

tips:java 字符串为空的情况

String a="";
String b=null;
System.out.println(a.isEmpty());
System.out.println(b.isEmpty());

在这里插入图片描述
生成流的例子:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class UseStream {
    public static void main(String[] args) {
        List<String> s= Arrays.asList("python"," ","xiaoxu","123","js","");
        System.out.println(s);
        System.out.println(s.getClass());
        System.out.println(s.stream().filter(str -> !str.isEmpty()));
        System.out.println(s.stream().filter(str -> !str.isEmpty()).collect(Collectors.toList()));
        System.out.println(s.stream().filter(str -> !str.isEmpty()).collect(Collectors.toList()).getClass());
        List<String> filtered=s.stream().filter(str -> !str.isEmpty()).collect(Collectors.toList());
        System.out.println(filtered);
        System.out.println(filtered.getClass());
    }
}

在这里插入图片描述
创建多种方式如下,stream可以通过集合数组创建:

1.通过java.util.Collection.stream(),java.util.Collection.parallelStream()用集合创建流
在这里插入图片描述

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class Mstream {
    public static void main(String[] args) {
        //1.通过java.util.Collection.stream(),java.util.Collection.parallelStream()创建
        List<String> s= Arrays.asList("a","b");
        //创建一个顺序流
        Stream<String> stream=s.stream();
        //创建一个并行流
        Stream<String> parallelStream=s.parallelStream();
    }
}

2.通过java.util.Arrays.stream(T[] array)方法用数组创建流:
在这里插入图片描述

import java.util.stream.IntStream;
import java.util.Arrays;

int[] arr={1,5,7};
IntStream ints_tream=Arrays.stream(arr);

3.使用Stream的静态方法:of()、iterate()、generate()
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import java.util.stream.Stream;

Stream<Integer> i1=Stream.of(1,8,9);
Stream<Integer> i2=Stream.iterate(5,x->x+3).limit(4);
i2.forEach(System.out::println);
Stream<Double> i3=Stream.generate(Math::random).limit(3);
i3.forEach(System.out::println);
5
8
11
14
0.02766533296035878
0.779837131876051
0.6171275733047784

4.stream和parallelStream简单区分:stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,前提是流中的数据处理没有顺序要求。如果流中的数据量足够大,并行流可以加快处理度。

除了直接创建并行流,还可以通过parallel()把顺序流转换成并行流:

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

List<Integer> ll=Arrays.asList(1,4,4,6);
Optional<Integer> k=ll.stream().parallel().filter(x->x==4).findFirst();
System.out.println(k.get());
4

5.Optional

Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

4 forEach

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

java中有多种方式对集合进行遍历,Collection.stream().forEach()和Collection.forEach()

4.1 增强for遍历集合

idea快捷导入类(import class),比如下面,在List后面光标,按下alt+enter,按下"import class",就会导入:import java.util.List
常见的java遍历集合的形式:增强for,输入a.for,idea快捷形成如下快捷方式:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
4.2 函数式java:Collection.forEach()遍历集合

使用函数式JavaCollection.forEach()遍历:

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class ForEac {
    public static void main(String[] args) {
        List<String> a= Arrays.asList("A","D","C","E");
        Consumer<String> consumer_me= System.out::println;
        a.forEach(consumer_me);
    }
}

在这里插入图片描述
4.3 集合流上调用:Collection.stream().forEach()

public static void main(String[] args) {
        List<String> a= Arrays.asList("A","D","C","E");
        Consumer<String> consumer_me= System.out::println;
        a.forEach(consumer_me);
        a.stream().forEach(consumer_me);
    }

在这里插入图片描述
4.4 Parallel Stream

并发流允许我们在多个线程中执行stream,在这种情况下,执行顺序也不明确的。Java只需要在调用任何最终操作(例如Collectors.toList() )之前完成所有线程。

public class ForEac {
    public static void main(String[] args) {
        List<String> a= Arrays.asList("A","D","C","E");
        Consumer<String> consumer_me= System.out::println;
        a.forEach(consumer_me);
//        a.stream().forEach(consumer_me);
        System.out.println("-----------------");
        a.parallelStream().forEach(System.out::println);
    }
}

并发流,并不会按照插入顺序打印:
在这里插入图片描述

4.5 列表中使用的forEach()会使用自定义迭代器,而stream().forEach()只是从列表中逐个获取元素,会忽略迭代器

4.6 两个forEach()方法之间的另一个细微差别是Java明确允许使用迭代器修改元素。相反,stream不能。

4.7 例子:以下代码片段使用 forEach 输出了10个随机数

public static void main(String[] args) {
  	Random random=new Random();
    System.out.println(random.ints());
    System.out.println(random.ints().limit(10));
    random.ints().limit(10).forEach(System.out::println);
}

在这里插入图片描述
5 map

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

public static void main(String[] args) {
    List<Integer> num= Arrays.asList(1,3,6,8,9,1);
    List<Integer> squareList=num.stream().map(i->i*i).distinct().collect(Collectors.toList());
    System.out.println(squareList);
}
[1, 9, 36, 64, 81]

6 filter

filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串

List<String> str=Arrays.asList("abc","","gh"," ","e");
List<String> fil_str=str.stream().filter(s->!s.isEmpty()).collect(Collectors.toList());
System.out.println(fil_str);
[abc, gh,  , e]

tips:因为字符串的isEmpty(),对于null来调用,会报空指针异常
在这里插入图片描述
在这里插入图片描述
所以在使用stream()的时候,要注意lambda方法中,异常数据是否会抛错的情况

7 limit

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

Random r=new Random();
r.ints().limit(10).forEach(System.out::println);

在这里插入图片描述
8 sorted

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序

Random r=new Random();
r.ints().limit(10).sorted().forEach(System.out::println);

在这里插入图片描述
9 Collectors

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

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

10 统计

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

import java.util.*;

public static void main(String[] args) {
        List<Integer> numbers=Arrays.asList(3,2,2,3,7,9,3);
        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());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值