一、函数式编程
函数式编程(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;
}
@Override
public 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进行的流式编程,希望对你能有所帮助。