Java 8新特性Stream流

本文详细介绍了Java 8中的Lambda表达式、方法引用、构造器引用和数组引用,以及流的概念和操作。Lambda表达式简化了代码,方法引用是其一种形式,用于直接引用已有方法。构造器引用则用于创建对象。数组引用允许创建指定类型的数组。流是处理数据的新方式,提供惰性求值和中间操作如filter、map、reduce等,以及收集操作如collect。文章通过实例展示了如何在实际编程中应用这些概念。

目录

Lambda表达式

方法引用

构造器引用

数组引用:

流是什么:

创建Stream

流的使用

收集:

使用例题:


Lambda表达式

方法引用

方法引用:若Lambda 体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用是Lambda 表达式的另一种表现形式)

主要有三种语法格式:

对象 :: 实例方法名

:: 静态方法名

:: 实例方法名

注意:

        1、Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的返回值类型保持一致

        2、若Lambda参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的惨数时,可以使用ClassName :: method

// 对象::实例方法名 例:
public void test(){
    PrinStream ps= System.out;
    Commsumer<String> con =(x) -> ps.println(x);  //Lambda 表达式
    
    PrintStream ps1 =System.out;
    Consumer<String> con1 =ps::println;   //Lambda 体中的内容有方法已经实现了,我们可以使用“方法引用”
    
    Consumer<String> con2 =System.out::println;
    con2.appect("dsda")
}
// 类::静态方法名 例:
public void test2(){
    Comparator<Integer> com =(x,y) -> Integer.compare(x,y);

    Comparator<Integer> com1= Integer::compare;
}
//类::实例方法名
public void test3(){
    BiPredicate<String,String> bp =(x,y)->x.equals(y);

    BiPredicate<String,String> bp1 = String::equals;
}

构造器引用

格式:

ClassName :: new

注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致

Supplier<Employee> sup = ()-> new Employee(); 
Supplier<Employee> sup1 = Employee :: new; //调用哪个构造器取决于Supplier函数的参数



Function<Interger,Employee> fun = (x) -> new Employee(x);
Function<Interger,Employee> fun1 = Employee :: new; //调用哪个构造器取决于Function函数的参数

数组引用:

格式:  Type :: new;

Function<Integer,String[]> fun = (x)-> new String[x];
String[] strs= fun.apply(10);

Function<Integer,String[]> fun = String[]::new;
String[] strs= fun.apply(15);

流是什么:


是数据渠道,用于操作数据源(集合、数组等)所生产的元素序列。

“集合讲的是数据,流讲的是计算!” 

注意:

1、Stream自己不会存储元素

2、Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。

3、Sream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Steam的操作三个步骤

创建Stream

一个数据源(如集合、数组),获取一个流

中间操作

一个中间操作链,对数据源的数据进行处理

终止操作

一个终止操作,执行中间操作链,并产生结果

流的使用

//1.可以通过Collection系列集合提供的steam()或parallelStram()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream;
//2.通过Arrays中的静态方法stream()获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);

//3.通过Stream类中的静态方法of()
Stream<String> stream3 = Stream.of("aa","bb","cc");

//4.创建无限流  
Stream<Integer> stream4 =Stream.iterate(0,(x)->x+2);
//迭代
stream.forEach(System.out::println);

//生成
Stream.generate(()->Math.random()),limit(5).forEach(System.out::println)

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值” 

//筛选与切片
//filter--接受Lambda,从流中排除某些元素。
//limit--截断流,使其元素不超过给定数量。
//skip(n)--跳过元素,返回一个扔掉前n个元素的流。若流汇总元素不足n个,则返回一个空流,与limit(n)互补
//distinct--筛选,通过流产生元素的hashCode()和equals()去除重复元素


//中间操作 不会执行任何的操作的
Stream<Employee> s =employees.stream()
                             .filter((e)-> e.getAge()>35);
//终止操作  只有终止操作之后才会一次性的执行全部任务,即“惰性求值”    //内部迭代
s.forEach(System.out::println);

//外部迭代
Iterator<Employee> it = employees.iterator();
while(it.hasNext()){
    System.out.println(it.next);
    }
//映射
//map--接收Lambda,将元素转换成为其他形式或提取信息。接受一个函数作为参数,
该函数会被应用到每个元素上,并将其映射成一个新的元素。flatMap--接受一个函
数作为参数,将流中的每一个值都换成另一个流,然后把所有流连接成一个流

public void test(){
    List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee")
    list.stream()
        .map((str)-> str.toUpperCase())
        .forEacch(System.out::println);


    employee.stream()
            .map(Employee::getName)
            .forEach(System.out::println);

System.out.println("---------------------------------------");
    Stream<String<Character>> stream =list.stream()
                        .map(Tests::filerCahacter);
    stream.forEach((sm)->{
        sm.forEach(System.out::println);
    })
System.out.println("---------------------------------------");
    Stream<Character> as = list.stream().flatmap(Tests::filerCahacter);
    
}
//查找与匹配
allMatch--检查是否匹配所有元素
anyMatch--检查是否至少匹配一个元素
noneMath--检查是否没有匹配一个元素
findFirst--检查是否至少匹配所有元素
findAny--返回第一个元素
count--返回流中元素的总个数
max--返回流中最大数
min--返回流中最小数

boolean b=employees.stream().allMatch((e)->e.getStatus.equals(Status.BUSY));
归约
reduce(T identity,BinaryOperator)/reduce(BinaryOperator)  -可以将流中元素反复结合起来,得到一个值
@Test
public void test(){
    List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8);
    //将起始0先作为x的第一个元素,从流中取得作为y
    list.stream().reduce(0,(x+y)-> x+y);
    
    //可能为空的封装到Opetional中
    Optional<Double> op = employees.stream()
                                   .map(Employee::getSalary)
                                   .reduce(Double::sum);
                                    
}

收集:


        Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法,可以方便地常见收集器实例。具体方法与实例如下:
 

List<String> list =employees.stream()
                   .map(Employee::getName)
                   .collect(Collectors.tolist());
//平均值
Double a =employees.stream()
                 .collect(Collectors.averagingDouble(Employee::getSalary));

//分组
Map<Status,list<Employee>> map =employees.stream()
                                .collect(Collectors.groupingBy(Employee::getStatus));

//多级分组
Map<Status,Map<String,list<Employee>>> map = employees.stream
                                             .collect(Collectots.groupingBy(Employee::getStatus,Collecctors.groupingBy((e)->{
    if(((Employee)e).getAge()<=12){return "ds"}}));

//分区
Map<Boolean,List<Employee>> map = employee.stream()
                            .collect(Collectors.partitioningBy((e)->e.getAge()>18));

使用例题:


1.给定一个数字列表,如返回一个每个数的平方构成列表呢:

        输入[1,3,5],输出[1,9,25]

public void test(){
Integer[] nums =new Integer[]{1,3,5};
Arrays.stream(nums)
      .map((x)-> x*x)
      .forEach(Systemou::println);
}

本人笔记

资料来源:尚学堂

<think>嗯,用户想学习Java 8Stream,该怎么教他们呢?首先得了解他们的背景。可能他们已经有一些Java基础,但没接触过Stream。需要从基础开始,逐步深入。 首先,得介绍Stream是什么。用户可能听说过Stream处理集合更方便,但具体概念还不清楚。要解释Stream和集合的区别,比如元素序列、源数据、函数式操作这些点。可能还要提到中间操作和终端操作的区别,比如filter是中间操作,collect是终端操作,这样他们不会混淆。 然后,需要举一些简单的例子,比如创建Stream的方式。从集合转换是最常见的,可以用stream()方法。数组的话用Arrays.stream,或者直接用Stream.of。例子要简单明了,比如用ListStream,这样用户能马上上手。 接下来是常用操作。filter、map、sorted这些中间操作,还有collect、forEach这些终端操作。每个操作都需要例子说明。比如用filter过滤字符串长度,用map转换成大写,sorted排序。例子代码要简洁,展示出链式调用的优势,对比传统循环,突出Stream的简洁性。 然后,可能用户会想知道更多高级操作,比如flatMap处理嵌套集合,reduce进行归约,还有统计操作如sum、average。这时候需要例子展示如何扁平化,比如把多个列表合并,或者计算总和。这些例子能帮助用户理解更复杂的场景。 并行也是一个重点,毕竟Stream的优势之一就是并行处理。需要解释parallelStream的使用,但也要提醒线程安全的问题,比如在reduce操作中累加器要符合规范,避免并发问题。例子用并行计算总和,对比串行,说明性能提升的可能性。 接下来,学习资源推荐。官方文档是必须的,但可能有些用户觉得枯燥,所以推荐一些书籍,比如《Java 8实战》,还有在线教程如Baeldung,这些资源比较友好。另外,实践项目很重要,可以建议他们用Stream重构旧代码,或者处理数据,比如统计日志信息,这样能巩固所学。 最后,注意事项部分要强调Stream的一次性消费,避免重复使用;区分中间和终端操作,防止遗漏终端操作导致不执行;性能方面,小数据可能传统循环更快,大数据用并行。这些注意事项能帮助用户避免常见错误。 整个思考过程中,要确保结构清晰,从概念到操作,再到高级特性和资源,逐步引导用户。例子要具体,避免太抽象的解释,让用户能动手实践。同时,提醒他们注意事项,避免踩坑。可能用户需要对比传统方式和Stream的区别,所以在例子中适当比较,突出Stream的优点。还要考虑用户可能遇到的问题,比如为什么终端操作没执行,或者并行的线程安全,提前给出提示。</think>要系统学习Java 8Stream,可以按以下步骤逐步掌握: --- ### 一、理解核心概念 1. **什么是Stream**: - 不是数据结构,而是对数据源(集合、数组等)进行函数式操作的水线 - 特点:不存储数据、不修改源数据、延迟执行 2. **与集合的区别**: $$集合 = 存储 + 操作数据 \quad vs \quad Stream = 声明式操作$$ --- ### 二、掌握基础操作 #### 1. 创建Stream ```java // 从集合创建 List<String> list = Arrays.asList("a", "b", "c"); Stream<String> stream = list.stream(); // 从数组创建 String[] array = {"a", "b"}; Stream<String> stream = Arrays.stream(array); // 直接创建 Stream<String> stream = Stream.of("a", "b"); ``` #### 2. 常用中间操作 ```java List<String> result = list.stream() .filter(s -> s.length() > 3) // 过滤 .map(String::toUpperCase) // 转换 .sorted() // 排序 .distinct() // 去重 .skip(1) // 跳过元素 .limit(5) // 限制数量 .collect(Collectors.toList()); // 终端操作 ``` --- ### 三、掌握进阶特性 #### 1. 并行 ```java long count = list.parallelStream() // 自动并行处理 .filter(s -> s.contains("a")) .count(); ``` #### 2. 数值(避免装箱) ```java IntStream.rangeClosed(1, 100) // 生成1-100的int .sum(); ``` #### 3. 高级收集器 ```java Map<Integer, List<String>> groupByLength = list.stream() .collect(Collectors.groupingBy(String::length)); String joined = list.stream() .collect(Collectors.joining(", ")); ``` --- ### 四、典型应用场景 1. **数据过滤**: ```java List<User> adults = users.stream() .filter(u -> u.getAge() >= 18) .collect(Collectors.toList()); ``` 2. **数据转换**: ```java List<String> emails = users.stream() .map(User::getEmail) .collect(Collectors.toList()); ``` 3. **统计计算**: ```java Double average = users.stream() .collect(Collectors.averagingInt(User::getAge)); ``` --- ### 五、学习资源推荐 1. **官方文档**: - [Java 8 Stream API](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html) 2. **实战书籍**: - 《Java 8实战》(Java 8 in Action) 3. **在线教程**: - Baeldung的[Java Stream指南](https://www.baeldung.com/java-8-streams) - 菜鸟教程的[Java 8新特性](https://www.runoob.com/java/java8-new-features.html) --- ### 六、练习建议 1. **重构现有代码**:将传统for循环改写成Stream操作 2. **解决实际问题**: - 统计日志文件中不同错误类型的出现次数 - 处理嵌套集合(如`List<List<Integer>>`) 3. **参与编程挑战**:在LeetCode等平台用Stream解题 --- ### 七、注意事项 1. **只能消费一次**:终端操作后即关闭 2. **区分中间/终端操作**:缺少终端操作时中间操作不会执行 3. **避免副作用**:不要在lambda表达式中修改外部变量 4. **性能权衡**:小数据集可能传统循环更快,大数据集用并行更高效 通过理论+实践结合,约20小时系统学习即可掌握核心用法。建议从简单案例入手,逐步尝试复杂场景的式处理。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值