一、函数式编程
函数式编程(Functional Programming,简称 FP)是一种编程范式,它强调将计算视为数学函数的评估,避免改变状态以及可变数据。与过程式编程和面向对象编程不同,函数式编程强调函数的纯洁性(即无副作用)和不可变性(即数据一旦创建就不能改变)。
在 Java 8 中,引入了函数式接口(Functional Interface)的概念,使得函数式编程在 Java 中也能得以实现。
二、函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。 java8引入@FunctionalInterface 注解声明该接口是一个函数式接口。
函数式接口是Java8支持函数式编程的基础,函数式接口允许开发者使用Lambda表达式来创建其实例。
三、常见的函数接口类型
断言式接口 Predicate<T>:接收 T 对象并返回 boolean。消费型接口 Consumer<T>:接收 T 对象,不返回值。函数型接口 Function<T, R>:接收 T 对象,返回 R 对象。供给型接口 Supplier<T>:提供 T 对象(例如工厂),不接收值。UnaryOperator<T>:接收 T 对象,返回 T 对象。BinaryOperator<T>:接收两个 T 对象,返回 T 对象。
四、Lambda表达式
Lambda表达式是Java 8中引入的一个核心特性,它允许我们以简洁、紧凑的方式表示一个匿名函数。Lambda表达式基于函数式编程的概念,允许我们定义一个接受特定参数并返回结果的函数,而无需为其指定一个名称。
Lambda表达式可以作为方法的参数使用,这使得代码更加简洁紧凑,并为函数式编程提供了支持。
Lambda表达式是一个对象,它必须赋给一个函数式接口,这种接口可以通过@FunctionalInterface显式指明,它只能有一个方法。
五、Stream流式编程
Stream API是Java 8引入的一个新特性,用于处理数据集合(如List、Set等)。它提供了一种声明性、函数式的方式来处理数据,支持过滤、映射、排序、聚合等操作。 以下是一些常用的流程编程操作代码示例:
准备测试数据
public class User {private String name;private Integer age;private String grade;private Integer score;public User(String name, Integer age, String grade, Integer score) {this.name = name;this.age = age;this.grade = grade;this.score = score;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getGrade() {return grade;}public void setGrade(String grade) {this.grade = grade;}public Integer getScore() {return score;}public void setScore(Integer score) {this.score = score;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", grade='" + grade + '\'' +", score=" + score +'}';}
}
User user1 = new User("张三", 6, "一年级", 70);User user2 = new User("李四", 7, "一年级", 75);User user3 = new User("王五", 7, "二年级", 80);User user4 = new User("赵六", 8, "三年级", 85);User user5 = new User("张飞", 5, "一年级", 90);List<User> userList = new ArrayList<>();userList.add(user1);userList.add(user2);userList.add(user3);userList.add(user4);userList.add(user5);
1. 遍历/匹配(foreach/find/match)
// 遍历输出数据
userList.forEach(user -> System.out.println(user));// 匹配查找第一个
Optional<User> firstUser = userList.stream().filter(user -> user.getAge() > 6).findFirst();
System.out.println(firstUser.get());// 随机匹配查找一个,parallelStream(并行流)
Optional<User> anyUser = userList.parallelStream().filter(user -> user.getAge() > 6).findAny();
System.out.println(anyUser.get());// 是否包含大于8的年龄的学生
boolean anyMatch = userList.stream().anyMatch(user -> user.getAge() > 8);
System.out.println(anyMatch);
2. map/flatMap
将流的元素映射成另一个类型
map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
// 获取名称到一个新的列表中
List<String> nameList = userList.stream().map(user -> user.getName()).collect(Collectors.toList());
System.out.println(nameList);
3. filter
对流的元素过滤
// filter 获取年龄=7的学生
List<User> ageList = userList.stream().filter(user -> user.getAge() == 7).collect(Collectors.toList());
System.out.println(ageList);
4. 聚合(max/min/count)
// 年龄最大的学生
Optional<User> maxUser = userList.stream().max(Comparator.comparing(User::getAge));
System.out.println(maxUser.get());// 年龄大于6的有几个人
long count = userList.stream().filter(user -> user.getAge() > 6).count();
System.out.println(count);
5. sorted
对流的元素排序
// 按照年龄进行 排序
List<User> sortedList = userList.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());
System.out.println(sortedList);// 先按照年龄排序,在按照分数排序,且排序方式使用自定义方式
List<User> sortedList2 = userList.stream().sorted((p1, p2) -> {if (p1.getAge() == p2.getAge()) {return p2.getScore() - p1.getScore();} else {return p2.getAge() - p1.getAge();}
}).collect(Collectors.toList());
System.out.println("sortedList2==" + JSONObject.toJSONString(sortedList2));
6. distinct
去除流中重复的元素
List<Integer> distinctList = userList.stream().map(User::getAge).distinct().collect(Collectors.toList());
System.out.println(distinctList);
7. reduce
对流中的元素归约操作,将每个元素合起来形成一个新的值
//分数的总合
Integer reduce = userList.stream().map(User::getScore).reduce((x, y) -> x + y).get();
System.out.println(reduce);
8. groupingBy
分组操作
// 按照年级分组
Map<String, List<User>> map1 = userList.stream().collect(Collectors.groupingBy(User::getGrade));
System.out.println("map1=" + JSONObject.toJSONString(map1));// 按照年龄段分组
Map<Integer, List<User>> map2 = userList.stream().collect(Collectors.groupingBy(user -> {if (user.getAge() <= 6) {return 1;} else if (user.getAge() == 7) {return 2;} else {return 3;}
}));
System.out.println("map2=" + JSONObject.toJSONString(map2));// 多级分组(按照年级分组之后,每个年级再按照年龄分组)
Map<String, Map<Integer, List<User>>> map3 = userList.stream().collect(Collectors.groupingBy(User::getGrade, Collectors.groupingBy(user -> {if (user.getAge() <= 6) {return 1;} else if (user.getAge() == 7) {return 2;} else {return 3;}
})));
System.out.println("map3=" + JSONObject.toJSONString(map3));
9. limit/skip
limit():截取流中前面几个元素
skip():跳过流中前面几个元素
// 从第一条数据开始,每2条出来
List<User> userList1 = userList.stream().skip(0).limit(2).collect(Collectors.toList());
System.out.println("userList1=" + JSONObject.toJSONString(userList1));
10. 两个列表取交集/并集
List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5);List<Integer> list2 = Arrays.asList(4, 5, 6, 7, 8);
// 交集
List<Integer> list3 = list1.stream().filter(item -> list2.contains(item)).collect(Collectors.toList());
System.out.println(list3);// 并集
List<Integer> list4 = Stream.concat(list1.stream(), list2.stream()).distinct().collect(Collectors.toList());
System.out.println(list4);
11. 根据列表中的对象某个属性进行去重
List<User> userList2 = userList.stream().collect(collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(User::getName))), ArrayList::new));System.out.println("userList2=="+JSONObject.toJSONString(userList2));
以上就是使用stream进行的流式编程,希望对你能有所帮助。