Java函数式编程Stream流

本文深入探讨Java函数式编程的基础概念与实践技巧,重点介绍lambda表达式及其应用,包括流的操作方法如filter、map、sorted等,以及如何通过forEach、count等终结操作处理数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java函数式编程

函数式编程主要关注于数据进行了哪些处理,最终得到我们想要的结果

一、lambda表达式

1、基本格式
(参数)->{数据处理代码块}

例一:创建线程并启动

方式一:匿名内部类

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("线程被调用了");
    }
}).start();

方式二:lambda表达式

/*
将接口、方法名都删掉就成了lambda表达式,可以理解为在此处,接口名、方法名是什么并不重要,重要的是参数有哪些,做了哪些处理,lambda表达式就是保留了这些我们关心的代码
*/
new Thread(()-> {
        System.out.println("线程被调用了");
    }
).start();

//最简形式
new Thread(() -> System.out.println("线程被调用了")).start();
2、使用lambda表达式前提
  • 原匿名内部类必须是一个接口
  • 接口只有一个需要重写的方法

如例子中,Runnable是一个接口,且只有一个run方法需要重写,满足lambda表达式的使用条件

3、lambda表达式的省略规则
  • 参数类型可以省略
  • 方法体只有一句代码时,大括号、return和分号都可以省略(如例一中的最简形式)
  • 方法只有一个参数时小括号可以省略,多个参数则用逗号分割

注意:以上三条不省略,代码也照样能运行,不是必要要求

4、常用操作
4.1、创建流
//数组
Integer[] arr = {};
//方式一
Stream<Integer> stream = Arrays.stream(arr);
//方式二
Stream<Integer> stream = Stream.of(arr);

//单列集合
List<Object> list = new ArrayList<>();
Stream<Object> stream = list.stream();

//双列集合
Stream<Map.Entry<Object, Object>> stream = map.entrySet().stream();
Stream<Object> stream = map.keySet().stream();
4.2、中间操作
4.2.1、filter

对流中的元素进行条件过滤,不符合过滤条件的都会被剔除

//找出年龄大于18岁的
List<Student> students = InstallData.getStudents();
students.stream()
        .filter(student -> student.getAge()>18)
        .forEach(age -> System.out.println(age));

以下代码示例都省略了调用InstallData.getStudents()获取students集合

4.2.2、distinct

去重

students.stream()
        .distinct()
        .forEach(student -> System.out.println(student.getName()));

注意:distinct方法是依赖于Object的equals方法判断对象是否相同,可根据需要重写equals方法

4.2.3、map

对流中的数据进行转换、提取

students.stream()
        .map(student -> student.getName())
        .forEach(name -> System.out.println(name));

结果:获取了students中所有的name

4.2.4、sorted

对流中的元素排序

有无参和有参两种,其中如果使用无参方法对对象进行排序,需要让对象实现Comparable接口,重写方法编写比较规则,否则会报错

//省略了lombok注解
public class Student implements Comparable<Student>{

    private Integer id;
    private String name;
    private Integer age;
    private List<Course> courseList;

    //设定Student对象之间按年龄排序
    @Override
    public int compareTo(Student s) {
        return this.getAge()-s.getAge();
    }
}
students.stream()
        .sorted()
        .forEach(student -> System.out.println(student.getAge()));
//输出15、15、16、18、20

比较常用的还是有参方法,不用特意的修改实体类,灵活的实现排序

students.stream()
        .sorted((s1, s2) -> s1.getAge() - s1.getAge())
        .forEach(student -> System.out.println(student.getAge()));
//输出结果同上
4.2.5、limit

限制流的最大长度,参数值为流的最大长度且必须大于等于零,否则报错

//配合排序,可以得到最小的年龄
students.stream()
        .sorted((s1, s2) -> s1.getAge() - s1.getAge())
        .limit(1)
        .forEach(student -> System.out.println(student.getAge()));
4.2.6、skip

跳过流中的元素,参数为跳过的数量

//配合sorted和limit可以获取第n小或第n大的数据
students.stream()
        .sorted((s1, s2) -> s1.getAge() - s1.getAge())
        .skip(2)
        .limit(1)
        .forEach(student -> System.out.println(student.getAge()));
4.2.6、flatMap

将流中的元素转为另一个流

//将student中的元素courseList转为流
Stream<Course> courseStream = students.stream()
        .flatMap(new Function<Student, Stream<Course>>() {
            @Override
            public Stream<Course> apply(Student student) {
                return student.getCourseList().stream();
            }
        });
4.3、终结操作
4.3.1、forEach

遍历流中的元素。

4.3.2、count、max&min

count获取流中元素个数

long count = students.stream()
        .distinct()
        .count();
System.out.println(count);

max&min获取最大、最小值

//获取年龄最大
Optional<Integer> max = students.stream()
        .distinct()
        .map(student -> student.getAge())
        .max((a1, a2) -> a1 - a2);
System.out.println(max.get());
4.3.3、collect

将流转化为集合,是终结操作中最常用的方法

//转为List集合
List<Integer> ages = students.stream()
        .distinct()
        .map(student -> student.getAge())
        .collect(Collectors.toList());

//转为Set集合
Set<Integer> ages = students.stream()
        .distinct()
        .map(student -> student.getAge())
        .collect(Collectors.toSet());

//转为Map集合,学生姓名为key,课程集合为value
Map<String, List<Course>> map = students.stream()
                .distinct()
                .collect(Collectors.toMap(student -> student.getName(), 
                                          student -> student.getCourseList()));
System.out.println(map);
4.3.4、anyMatch、allMatch&noneMatch

anyMatch判断流中是否存在符合条件的元素

//年龄是否有大于18岁的学生
boolean b = students.stream()
        .distinct()
        .anyMatch(student -> student.getAge() > 18);
System.out.println(b);

allMatch判断流中的元素是否都符合条件

noneMatch判断流中的元素是否都不符合条件

4.3.5、findFirst

查找流中第一个匹配条件的元素

Integer[] arr = {15,17,20,14,28};
Optional<Integer> optional = Arrays.stream(arr)
        .filter(a -> a>18)
        .findFirst();
System.out.println(optional.get());
4.3.5、reduce

对流的元素执行归约,并返回归约后的值

  • 两个参数的重载形式

上图为该重载形式的说明,简单的说就是第一个参数是初始值,第二个参数是进行归约的具体代码块

例如

//求学生中的最小年龄
Integer max = students.stream()
        .distinct()
        .map(student -> student.getAge())
        .reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() {
            @Override
            public Integer apply(Integer result, Integer element) {
                return result > element ? result : element;
            }
        });
System.out.println(max);

//lambda
Integer max = students.stream()
        .distinct()
        .map(student -> student.getAge())
        .reduce(Integer.MIN_VALUE, (result, element) -> result>element ? result:element);
System.out.println(max);
  • 一个参数的重载形式

其实就是在两个参数的重载形式上,将初始值设为第一个元素的值,相当于不再把最小年龄初始为Integer.MIN_VALUE,而是初始为流中第一个年龄

//求学生中的最小年龄
Optional<Integer> optional = students.stream()
        .distinct()
        .map(student -> student.getAge())
        .reduce((result, element) -> result > element ? result : element);
System.out.println(optional.get());

更多关于Optional容器使用请看:“java Optional容器的使用”

注意事项

1.如果Stream流没有终结操作,则中间操作也不会执行
2.创建的流只能被终结操作一次,经过终结操作后,不能再被使用了,否则会报错
3.流操作是不会影响原数据的

备注

以下为示例中所用到的相关对象、代码

//学生类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student{
    private Integer id;
    private String name;
    private Integer age;
    private List<Course> courseList;
}
//课程类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Course {
    private String courseName;
    private Integer score;
}
//组装数据
public class InstallData {

    public static List<Student> getStudents(){
        List<Course> courseList1 = new ArrayList<>();
        Course chemistry = new Course("chemistry", 60);
        courseList1.add(chemistry);
        courseList1.add(new Course("math",66));
        courseList1.add(new Course("physical",63));

        List<Course> courseList2 = new ArrayList<>();
        courseList2.add(new Course("chemistry",70));
        courseList2.add(new Course("math",69));
        courseList2.add(new Course("physical",60));

        List<Course> courseList3 = new ArrayList<>();
        courseList3.add(new Course("chemistry",90));
        courseList3.add(new Course("math",95));
        courseList3.add(new Course("physical",99));

        List<Course> courseList4 = new ArrayList<>();
        courseList4.add(new Course("chemistry",83));
        courseList4.add(new Course("math",79));
        courseList4.add(new Course("physical",90));

        Student zhangsan = new Student(1,"zhangsan",15,courseList1);
        Student zhangsan1 = new Student(1,"zhangsan",15,courseList1);
        Student lisi = new Student(2,"lisi",16,courseList2);
        Student wangwu = new Student(3,"wangwu",20,courseList3);
        Student zhaoliu = new Student(4,"zhaoliu",18,courseList4);
        List<Student> students = new ArrayList<>();
        students.add(zhangsan);
        students.add(zhangsan1);
        students.add(lisi);
        students.add(wangwu);
        students.add(zhaoliu);

        return students;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值