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;
}
}