Java中Stream流库知识总结:流的创建、常用的中间和终结操作

Java流库

Java中的流库是从Java 8中引入的,遵循“做什么而非怎么做”的原则。

与集合相比,流提供了一种可以让我们在更高的概念级别上指定计算任务的数据视图,它不存储其元素,操作不会修改其数据源同时尽可能惰性执行,这一位直至只需要其结果时操作才会执行。

操作流的典型流程包括三个阶段:

  1. 创建一个流。

  2. 指定将初始流转换为其他流的中间操作,可能包含多个步骤。

  3. 应用终止操作,从而产生结果。这个操作会强制执行之前的惰性操作。此后这个流就不能用了。


流的创建

给定数据流的创建

1. 通过集合

Collection<E>的方法说明
default Stream<E> stream()产生当前集合中所有元素的顺序流

注:Map集合需要先调用entrySet()方法进行间接调用。

Collection list=new ArrayList<Integer>();
Map hashmap=new HashMap<String,Double>();
Stream<Integer> stream1=list.stream();
Stream<Map.Entry<String,Double>> stream2 = hashmap.entrySet().stream();

2. 通过数组

Arrays的方法说明
static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive)产生一个流,它的元素是由数组中指定范围内的元素构成的(参数startInclusive和endExclusive允许为空)。
String[] array=new String[]{"北京","上海","广州","深圳"};
Stream<String> stream3=Arrays.stream(array);

3. 通过零散数据

Stream的方法说明
static<T> Stream <T> of(T… values)产生一个元素为给定值的流。
Stream<Character> stream4=Stream.of('a','b','c','d');

空流的创建

Stream的方法说明
static<T> Stream <T> empty()产生一个不包含任何元素的流
Stream<String> stream5=Stream.empty();

无限流的创建

Stream方法说明
static<T> Stream<T> generate(Supplier<? extends T> s)产生一个无限流,它的值是通过反复调用函数s构建的。
static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)产生一个无限流,它的元素包含seed、在seed上调用f产生的值、在前一个元素上调用f产生的值,等等。()
Stream<String> stream6=Stream.generate(()->"Echo");
Stream<BigInteger> stream7=Stream.iterate(BigInteger.ZERO,n->n.add(BigInteger.ONE));

常用的中间操作

过滤和映射

Stream方法说明
Stream<T> filter(Predicate<? super T> predicate)产生一个流,它包含当前流中所有满足谓词条件的元素
<R> Stream<R> map(Function<? super T, ? extends R> mapper)产生一个流,它包含将mapper应用于当前流中所有元素所产生的结果
ArrayList<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
Stream<Integer> st1_1 = list.stream().filter(n->n>2); //结果为3 4 
Stream<Integer> st1_2 = list.stream().map(n->n*2);    //结果为2 4 6 8 

抽取和组合

Stream方法说明
Stream<T> limit(long maxSize)产生一个流,其中包含了当前流中最初的maxSize个元素
Stream<T> skip(long n)产生一个流,它的元素包是当前流中除了前n个元素之外的所有元素
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)产生一个流,它的元素是a的元素后面跟着b的元素
Stream<Integer> a = list.stream().limit(3); //结果为1 2 3
Stream<Integer> b = list.stream().skip(1);  //结果为2 3 4
Stream<Integer> con = Stream.concat(a, b);  //结果为1 2 3 2 3 4

流对象如果被消费过了就不允许再次使用,如上述例子中使用了a和b进行合并,如果再调用流a或流b系统将会报错。

排序和去重

Stream方法说明
Stream<T> distinct()产生一个流,包含当前流中所有不同的元素
Stream<T> sorted()产生一个流,它的元素是当前流中所有元素按照顺序排列的
HashSet<Character> list2=new HashSet<>();
list2.add('H');
list2.add('a');
list2.add('i');
list2.add('N');
list2.add('a');
list2.add('n');
Stream<Character> st2_1 = list2.stream().distinct(); //结果为H a i N n
Stream<Character> st2_2 = list2.stream().sorted();   //结果为H N a a i n

常用终结操作

流的计数

Stream方法说明
long count产生当前流中元素的数量
long count = list2.stream().count();
System.out.println(count);

遍历元素(输出元素)

Stream方法说明
void forEach(Consumer<? super ? T > action)在流的每个元素上调用action
//输出list2集合中前两个小写字母
list2.stream().
    filter(c->c>='a'&&c<='z').
    distinct().
    limit(2).
    forEach(c->System.out.println(c));
//为方便展示进行分行,实质上以上为一条代码

Stream流支持链式编程,中间方法调用完后生成新的Stream流可以继续使用,但应用终结操作后就不能再使用了。

收集结果

Stream方法说明
<R,A> R collect(Collector<? super T,A,R> collector使用给定的收集器来收集当前流中的元素,Collectors类有用于多种收集器的工厂方法
Collectors方法说明
static <T> Collector<T, ?, List<T>> toList()把元素收集到List集合中
static <T> Collector<T, ?, Set<T>> toSet()把元素收集到Set集合中
static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)把元素收集到Map集合中
//将list集合前两个元素存到新的List集合中
List<Integer> collect1 = list.stream().limit(2).collect(Collectors.toList());

//将list2集合去重后存到新的Set集合中
Set<Character> collect2 = list2.stream().distinct().collect(Collectors.toSet());

//将下列List集合中大于24岁的人存入新的Map集合中
ArrayList<String> nameAge=new ArrayList<>();
nameAge.add("张三,23");
nameAge.add("李四,24");
nameAge.add("王五,25");
nameAge.add("赵六,26");
Map<String, Integer> map = nameAge.stream().
        filter(s -> Integer.parseInt(s.split(",")[1]) >= 24).
        collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));
System.out.println(map);

前面的函数式接口对象基本都是以lambda表达式的形式进行书写,也可以根据个人选用匿名类的表达形式,如toMap方法用后者可能更能增加程序可读性。


参考资料

  1. 《Java核心技术·卷Ⅱ 高级特性(原书第11版)》第1章 Java8的流库

  2. 黑马程序员-2023新版Java视频教程-进阶篇Day12-01-Stream流

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

STRANGEX-03

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值