Java从入门到精通十七(Stream 流)

简介: Stream 流引入说明这是java8 引入的新的特性和之前介绍的java IO 流多多少少有所区别。简单的说IO就是进行了基本的数据传输操作,Stream是对集合的数据进行过滤操作。主要就是对集合进行操作。IO涉及比较广,主要还是进行数据的传输。

Stream 流引入说明


这是java8 引入的新的特性


和之前介绍的java IO 流多多少少有所区别。简单的说IO就是进行了基本的数据传输操作,Stream是对集合的数据进行过滤操作。主要就是对集合进行操作。IO涉及比较广,主要还是进行数据的传输。


相比较集合的话就是一般是配合使用的。集合是用来对数据进行一个存储,不会对数据进行其它形式的处理,主要就是存储。Stream是会对数据处理的,判断,过滤,计算都有。


一般在对集合中的数据进行处理的话,结合Stream可以非常方便进行操作。我们一般还是配合Lambda表达式的模式进行处理。代码比较简化优雅。


Stream 流的常用方法说明

1: filter()

filter(Predicate<? super T> predicate)

返回由与此给定谓词匹配的此流的元素组成的流。

会返回判断条件为true的元素,这个方法会返回一个流


如下,我们先用filter 来返回判断结果为true的流,然后再调用collect中的方法让它返回集合。


ArrayList<String> list = new ArrayList<>();
        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("张敏");
        list.add("张无忌");
        List<String> list_ = list.stream().filter(s -> s.startsWith("张")).collect(Collectors.toList());


2:collect()

至于collect方法,我们主要需要了解它的一些用法。


collect(Collector<? super T,A,R> collector)


1.Collectors.toList():转换成List集合。/ Collectors.toSet():转换成set集合。


List<String> list_de = list.stream().collect(Collectors.toList());


2:Collectors.toCollection(TreeSet::new):转换成特定的set集合。


TreeSet<String> treeset = list.stream().collect(Collectors.toCollection(TreeSet::new));


3:Collectors.toMap(keyMapper, valueMapper, mergeFunction):转换成map


这个方法包含三个重载方法

toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper);
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
        BinaryOperator<U> mergeFunction);
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
        BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier);


keyMapper:Key 的映射函数

valueMapper:Value 的映射函数

mergeFunction:当 Key 冲突时,调用的合并方法

mapSupplier:Map 构造器,在需要返回特定的 Map 时使用


需要注意的是如果键出现重复或者值为空的时候可能出现异常.所以再转换map的时候可以对值得冲突首先做处理.


简单举例

先创建一个类,Student_clo


package Stream;
public class Student_clo<S, I extends Number, S1> {
    private String name;
    private Integer age;
    private String id;
    public Student_clo(S jgdabc, I i, S snka) {
        this.name = (String) jgdabc;
        this.age = (Integer) i;
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
}
**测试类的使用**


package Stream;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
public class Student_Collection {
    public static void main(String[] args) {
//        Student_clo student_clo = new Student_clo();
//        Student_clo student_1_clo = new Student_clo();
//        Student_clo student_2_clo = new Student_clo();
        ArrayList<Student_clo<String,Integer,String>> student = new ArrayList<>(3);
        student.add(new Student_clo<>("jgdabc",12,"snka"));
        student.add(new Student_clo<>("jgdb",13,"45"));
        student.add(new Student_clo<>("sjns",19,"asjsa"));
//        v1,v2 这边对可能出现的键冲突进行了处理,只是用一下方法
        student.stream().collect(Collectors.toMap(Student_clo::getAge, Student_clo::getName,(v1,v2)->v2));
    }
}


3:distinct()


3:distinct() 方法


这个方法得作用是比较简单的,就是用来去除重复的元素。操作对象也是为流对象。


4:sorted()/sorted()


4: sorted()/sorted(T,T)->int)


方法的主要作用就是实现一个排序。如果流中的元素实现了Comparable接口,有自己的排序规则,就可以直接调用sorted() 方法,如果没有实现排序接口,那么需要调用sorted((T,T)->int )去实现排序接口。


定义一个基本类


package Stream;
public class Student_clo<S, I extends Number, S1> {
    private String name;
    private Integer age;
    private String id;
    public Student_clo(S jgdabc, I i, S snka) {
        this.name = (String) jgdabc;
        this.age = (Integer) i;
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
}


package Stream;
import javax.sound.midi.Soundbank;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Student_Collection {
    public static void main(String[] args) {
//        Student_clo student_clo = new Student_clo();
//        Student_clo student_1_clo = new Student_clo();
//        Student_clo student_2_clo = new Student_clo();
        ArrayList<Student_clo<String,Integer,String>> student = new ArrayList<>(3);
        student.add(new Student_clo<>("jgdabc",12,"snka"));
        student.add(new Student_clo<>("jgdb",11,"45"));
        student.add(new Student_clo<>("sjns",19,"asjsa"));
        List<Student_clo<String, Integer, String>> list_sort = student.stream().sorted((p1,p2)->p1.getAge()-p2.getAge()).collect(Collectors.toList());
        for(Student_clo l: list_sort)
        {
            System.out.println(l.getAge()+l.getName());
        }
        System.out.println(list_sort);
    }
}


5: limit()

5:limit(long n)

返回前n个元素,也就是对处理返回的元素做一个限制


List<Student_clo<String, Integer, String>> list_sort = student.stream().sorted((p1,p2)->p1.getAge()-p2.getAge()).limit(2).collect(Collectors.toList());


6:skip()

6:skip(long n)

这个方法是用来过滤掉前n个元素,也可以认为是跳过


 

List<Student_clo<String, Integer, String>> list_sort = student.stream().sorted((p1,p2)->p1.getAge()-p2.getAge()).limit(2).skip(1).collect(Collectors.toList());


7:forEach()

7:forEach() 方法

该方法可用于对集合进行一个遍历输出


8:map()

8:映射(转换):map

实现将流中的元素映射到另一个流当中

其中接口类型为Function,在写lambda需要注意一下泛型接口就可以


list.stream().map(s->Integer.parseInt(s)).forEach(System.out::println);


9:count()

9:count()

也可以认为是一个终结方法,主要是对元素进行计数,例如返回的的计数。比较简单,对象当然还是操作在Stream流上。


10:concat()

10:concat()方法

对流进行一个合并


// 取前四个数据组成一个流
        Stream<String> s1 = list.stream().limit(4);
        //跳过两个数据组成一个流
        Stream<String> s2 = list.stream().skip(2);
        //合并需求两个流
        Stream.concat(s1,s2).forEach(System.out::println);


11:flatMap()

11:flatMap()

对比map 方法的话,区别在于如果map中有流中嵌套了,那么一次遍历是得不到想要的结果的,需要两次遍历,如果我们要flapMap它只需要一次遍历,也就是它会把每个流打开,那么当然只需要一次遍历。


12: peek()

12 peek() peek 函数会按照消费接口Consumer函数进行消费处理,并可以改变函数的一些属性。


list.stream().peek(s-> System.out.println(s));
  list.stream().peek(System.out::print);
  list.stream().peek(StringBuffer::new);


13:iterate()

13:iterate() 方法

返回有序无限连续 Stream由函数的迭代应用产生 f至初始元素 seed ,产生 Stream包括 seed , f(seed) , f(f(seed)) ,等


Stream.iterate(0,x->x+1).limit(6).forEach(System.out::println);
        //0,1,2,3,4,5


14: reduce()

14: reduce() 方法

对集合形成的流对象进行一个归约

使用 associative累积函数对此流的元素执行 reduction ,并返回描述减小值的 Optional (如果有)。


8的api说的十分精准而难懂。


我们可以用它来做对集合形成的流对象中的元素进行求和。


ArrayList<Integer> list_i = new ArrayList<>();
        list_i.add(1);
        list_i.add(2);
        list_i.add(3);
        Integer sum = list_i.stream().reduce(0, Integer::sum);
        System.out.println(sum);//6


15: max()/min()

15: max()/min() 方法

还是操作流对象,只不过可以用这个方法来进行获取最大的对象,继而获取值。


先定义了一个Student_clo类


package Stream;
public class Student_clo<S, I extends Number, S1> {
    private String name;
    private Integer age;
    private String id;
    public Student_clo(S jgdabc, I i, S snka) {
        this.name = (String) jgdabc;
        this.age = (Integer) i;
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
}


ArrayList<Student_clo<String,Integer,String>> student = new ArrayList<>(3);
        student.add(new Student_clo<>("jgdabc",12,"snka"));
        student.add(new Student_clo<>("jgdb",11,"45"));
        student.add(new Student_clo<>("sjns",19,"asjsa"));
        Optional<Student_clo<String, Integer, String>> max = student.stream().max((e1, e2) -> e1.getAge() - e2.getAge());
        System.out.println(max.get().getAge());//返回到最大年龄为19


16:allMatch()/anyMatch()/noneMatch()

16:allMatch()/anyMatch()/noneMatch()

很明显就是作为匹配,分别对应全部匹配,一个或者一个以上的匹配,不匹配。如果满足对应的条件,就返回True,反之,返回false。

具体去用的话就十分清楚明了。


boolean b = list_i.stream().allMatch(i -> i > 0);
  boolean b1 = list_i.stream().anyMatch(i -> i > 2);
  boolean b2 = list_i.stream().noneMatch(i -> i - 3 >= 0);


创建Stream 流

通过Collection集合提供的stream()方法

在介绍方法的上面已经说明了。就是Collection集合系列。基本该说的都说了。前面运用的方法基本都是在集合的基础上进行说明。


Stream<String> stream2 = list.stream();


使用数组

用流将数组包围起来以后,就可以更加方便的使用一些方法(Stream流上的一些处理)


String arr[] = {"jgdabc","dnkas","esfnsa"};
        Stream<String> arr1 = Stream.of(arr);
        Stream<String> limit = arr1.limit(1);
        limit.forEach(System.out::println);


也可以使用数组中的方法去转换为stream流


final IntStream stream1 = Arrays.stream(new int[]{1, 2, 3});


Stream.iterate()

完整格式


Stream.iterate(final T seed, final UnaryOperator f)


基本在方法说明上也说了。

从参数上具体分析的话,就是一个常量seed,可指定泛型,然后呢,生成到f,f是UnaryOpeartor类型的。


这个类型是什么呢?查看源码的话,还是返现也就是一个继承Function的接口,然后里面有一个静态的方法。


很明显的就是一个函数式接口,稍微了解下就好。


@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
    /**
     * Returns a unary operator that always returns its input argument.
     *
     * @param <T> the type of the input and output of the operator
     * @return a unary operator that always returns its input argument
     */
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}


具体使用这个iterate的时候也就可以正如上面方法中提到的。做到一个类似遍历取值的效果。


Stream.iterate(0, n -> n + 1).limit(5).forEach(a -> {
            System.out.println(a);//0,1,2,3,4
        });


Stream.generate()

其实和iterate一样创建的是无限流。


怎么体现,随机数生成,就可以体现。因为无限流的特点,一般需要用limit()去进行限制。配合使用。还是挺好玩的。只要了解到lambda,函数式编程,好奇的话,看看源码,接口,就完事。


如果你不限制的话,生成时不会结束的。有趣。


 

Stream<Integer> stream = Stream.generate(() -> new Random().nextInt(10));


限制一下


Stream<Integer> stream = Stream.generate(() -> new Random().nextInt(10)).limit(10);
        stream.forEach(e -> System.out.println(e));


parallelStream(并行流)

我们也可以去用一个并行流


其实这个流,可以直接放在集合这边去归结,但是感觉这个并行流还是十分有特点的。并行的一个流,采用了多线程的方式。既然采用多线程,那么如果我foreach()进行终结遍历stream所包含的集合的元素,那么一个输出无需。为了好区分,避开使用set集合去验证这个特点。


ArrayList<String> list = new ArrayList<>();
list.add("10");
list.add("20");
list.add("30");
list.add("13");
list.add("50");
Integer arr[] = {1,2,3,4};
list.parallelStream().forEach(System.out::println);



并行可以提高效率,原理使用的还是forkjoin线程池。就简单介绍一下。从集合Collection的并行流的这个方法一直追溯源码的话,会一直找到其实是使用了forkjoin线程池。


相关文章
|
28天前
|
IDE Java 数据挖掘
Java 基础类从入门到精通实操指南
这份指南专注于**Java 17+**的新特性和基础类库的现代化用法,涵盖开发环境配置、数据类型增强(如文本块)、字符串与集合处理进阶、异常改进(如密封类)、IO操作及实战案例。通过具体代码示例,如CSV数据分析工具,帮助开发者掌握高效编程技巧。同时提供性能优化建议和常用第三方库推荐,适合从入门到精通的Java学习者。资源链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
111 34
|
19天前
|
Java API 微服务
2025 年 Java 从入门到精通学习笔记全新版
《Java学习笔记:从入门到精通(2025更新版)》是一本全面覆盖Java开发核心技能的指南,适合零基础到高级开发者。内容包括Java基础(如开发环境配置、核心语法增强)、面向对象编程(密封类、接口增强)、进阶技术(虚拟线程、结构化并发、向量API)、实用类库与框架(HTTP客户端、Spring Boot)、微服务与云原生(容器化、Kubernetes)、响应式编程(Reactor、WebFlux)、函数式编程(Stream API)、测试技术(JUnit 5、Mockito)、数据持久化(JPA、R2DBC)以及实战项目(Todo应用)。
75 5
|
27天前
|
监控 Java 测试技术
2025 年 Java 核心技术从入门到精通实战指南
《2025年Java核心技术实战指南》全面覆盖Java开发的最新趋势与最佳实践。内容包括Java新特性(如模式匹配、文本块、记录类)、微服务架构(Spring Boot 3.0+、Spring Cloud)、响应式编程(Reactor、WebFlux)、容器化与云原生(Docker、Kubernetes)、数据访问技术(JPA、R2DBC)、函数式编程、单元测试与集成测试(JUnit 5、Mockito)、性能优化与监控等。通过实战案例,帮助开发者掌握构建高性能、高可用系统的技能。代码资源可从[链接](https://pan.quark.cn/s/14fcf913bae6)获取。
115 7
|
28天前
|
消息中间件 Java 微服务
2025 版 Java 学习路线实战指南从入门到精通
《Java学习路线实战指南(2025版)》是一份全面的Java开发学习手册,涵盖基础环境搭建、核心语法与新特性、数据结构与算法、微服务架构、云原生技术栈、AI融合及项目实战。内容包括JDK安装配置、IntelliJ IDEA设置、Records类与模式匹配增强、LeetCode题解、Spring Cloud微服务开发、Kubernetes部署、OpenAI API调用等。结合在线商城系统案例,采用Vue 3、Spring Boot 3.5、MySQL、Elasticsearch等技术,提供从理论到实践的完整路径,助力开发者掌握2025年最新趋势与最佳实践。
142 4
|
16天前
|
Oracle Java 关系型数据库
java 入门学习视频_2025 最新 java 入门零基础学习视频教程
《Java 21 入门实操指南(2025年版)》提供了Java最新特性的开发指导。首先介绍了JDK 21和IntelliJ IDEA 2025.1的环境配置,包括环境变量设置和预览功能启用。重点讲解了Java 21三大核心特性:虚拟线程简化高并发编程,Record模式优化数据解构,字符串模板提升字符串拼接可读性。最后通过图书管理系统案例,展示如何运用Record定义实体类、使用Stream API进行数据操作,以及结合字符串模板实现控制台交互。该指南完整呈现了从环境搭建到实际项目开发的Java 21全流程实
44 1
|
20天前
|
算法 Java 测试技术
Java 从入门到实战完整学习路径与项目实战指南
本文详细介绍了“Java从入门到实战”的学习路径与应用实例,涵盖基础、进阶、框架工具及项目实战四个阶段。内容包括环境搭建、语法基础、面向对象编程,数据结构与算法、多线程并发、JVM原理,以及Spring框架等核心技术。通过学生管理系统、文件下载器和博客系统等实例,帮助读者将理论应用于实践。最后,提供全链路电商系统的开发方案,涉及前后端技术栈与分布式架构。附代码资源链接,助力成为合格的Java开发者。
47 4
|
25天前
|
监控 Java API
Java 异步编程难题拆解实操指南:从入门到精通解决异步编程关键问题
本文深入探讨了Java异步编程的实操技巧,基于Project Reactor与Spring WebFlux等技术框架,通过具体案例解决常见难题。内容涵盖反应式编程基础、回调地狱解决方案、并行任务处理、响应式REST API开发、背压策略应用、微服务异步通信及性能监控等方面。结合代码示例,详细讲解了如何构建高性能异步应用,并总结了最佳实践,帮助开发者掌握异步编程的核心技能。适合希望提升异步开发能力的技术人员阅读。
41 3
|
1月前
|
前端开发 Java 微服务
2025 年全网超全 Java 从入门到精通学习路线指南
这是一份全面的Java学习路线图,涵盖从基础到进阶的知识体系。基础阶段包括环境搭建、语法学习与面向对象编程;进阶阶段深入数据结构、多线程、JVM原理及泛型集合;框架阶段掌握Spring、MyBatis等工具;数据库阶段学习SQL、MySQL及Redis;前端技术涉及HTML、CSS与Vue;分布式阶段探讨微服务架构、Docker与Kubernetes;最后通过企业级项目实战提升性能优化与代码重构能力。资源地址:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)
438 7
|
1月前
|
Java 数据库连接 API
2025 更新必看:Java 编程基础入门级超级完整版指南
本教程为2025更新版Java编程基础入门指南,涵盖开发环境搭建(SDKMAN!管理JDK、VS Code配置)、Java 17+新特性(文本块、Switch表达式增强、Record类)、面向对象编程(接口默认方法、抽象类与模板方法)、集合框架深度应用(Stream API高级操作、并发集合)、模式匹配与密封类等。还包括学生成绩管理系统实战项目,涉及Maven构建、Lombok简化代码、JDBC数据库操作及JavaFX界面开发。同时提供JUnit测试、日志框架使用技巧及进阶学习资源推荐,助你掌握Java核心技术并迈向高级开发。
134 5
|
20天前
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
72 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问