Java8新特性
Java8 新增了非常多的特性,我们主要讨论以下几个:
- Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
- Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
Java 8 Stream API 函数式接口全解析:业务案例与代码实现
在Java 8中,Stream API 引入了一种新的处理集合数据的方式,使得我们可以以声明式的方式处理数据集合。以下是Stream API中一些关键函数式接口的详细业务案例。
1. Stream 的 filter
业务数据:一系列用户的年龄。
List<Integer> ages = Arrays.asList(22, 34, 29, 17, 30);函数使用:
Predicate<Integer> isAdult = age -> age >= 18;
long adultCount = ages.stream()
.filter(isAdult)
.count();输出结果:
描述:计算成年人的数量
结果值:成年人数为 42. Stream 的 map
业务数据:一系列用户的姓名。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");函数使用:
Function<String, String> toUpperCase = String::toUpperCase;
List<String> upperCaseNames = names.stream()
.map(toUpperCase)
.collect(Collectors.toList());输出结果:
描述:将所有姓名转换为大写
结果值:["ALICE", "BOB", "CHARLIE"]3. Stream 的 flatMap
业务数据:一系列用户的姓名和地址。
List<User> users = Arrays.asList(
new User("Alice", Arrays.asList("123 Apple St.", "456 Banana Ave.")),
new User("Bob", Arrays.asList("789 Cherry Blvd."))
);函数使用:
Function<User, Stream<String>> expandAddresses = user -> user.getAddresses().stream();
List<String> allAddresses = users.stream()
.flatMap(expandAddresses)
.collect(Collectors.toList());输出结果:
描述:获取所有用户的地址
结果值:["123 Apple St.", "456 Banana Ave.", "789 Cherry Blvd."]4. Stream 的 distinct
业务数据:一系列重复的字符串。
List<String> strings = Arrays.asList("apple", "banana", "apple", "orange", "banana");函数使用:
Set<String> distinctStrings = strings.stream()
.distinct()
.collect(Collectors.toSet());输出结果:
描述:获取不重复的字符串集合
结果值:["apple", "banana", "orange"]5. Stream 的 sorted
业务数据:一系列字符串。
List<String> strings = Arrays.asList("banana", "apple", "cherry");函数使用:
List<String> sortedStrings = strings.stream()
.sorted()
.collect(Collectors.toList());输出结果:
描述:按字典顺序排序字符串
结果值:["apple", "banana", "cherry"]6. Stream 的 limit
业务数据:一系列数字。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);函数使用:
List<Integer> firstThreeNumbers = numbers.stream()
.limit(3)
.collect(Collectors.toList());输出结果:
描述:获取前三个数字
结果值:[1, 2, 3]7. Stream 的 skip
业务数据:一系列字符串。
List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");函数使用:
List<String> fruitsAfterBanana = fruits.stream()
.skip(2)
.collect(Collectors.toList());输出结果:
描述:跳过前两个字符串,获取剩余的字符串
结果值:["cherry", "date", "elderberry"]8. Stream 的 forEach
业务数据:一系列员工的姓名。
List<String> employeeNames = Arrays.asList("Alice", "Bob", "Charlie");函数使用:
Consumer<String> printName = name -> System.out.println("Employee: " + name);
employeeNames.forEach(printName);输出结果:
描述:打印每个员工的姓名
结果值:
Employee: Alice
Employee: Bob
Employee: Charlie9. Stream 的 reduce
业务数据:一系列数字。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);函数使用:
Optional<Integer> sum = numbers.stream()
.reduce(Integer::sum);输出结果:
描述:计算数字总和
结果值:总和为 1010. Stream 的 collect
业务数据:一系列字符串。
List<String> strings = Arrays.asList("apple", "banana", "cherry");函数使用:
List<String> sortedStrings = strings.stream()
.sorted()
.collect(Collectors.toList());输出结果:
描述:按字典顺序排序字符串并收集到列表
结果值:["apple", "banana", "cherry"]11. Stream 的 min 和 max
业务数据:一系列数字。
List<Integer> numbers = Arrays.asList(1, 3, 2, 5, 4);函数使用:
Optional<Integer> min = numbers.stream()
.min(Integer::compare);
Optional<Integer> max = numbers.stream()
.max(Integer::compare);输出结果:
描述:找出数字中的最小值和最大值
结果值:最小值为 1,最大值为 512. Stream 的 count
业务数据:一系列字符串。
List<String> strings = Arrays.asList("apple", "banana", "cherry");函数使用:
long count = strings.stream()
.count();输出结果:
描述:计算字符串的数量
结果值:数量为 313. Stream 的 anyMatch
业务数据:一系列字符串。
List<String> strings = Arrays.asList("apple", "banana", "cherry");函数使用:
boolean hasBanana = strings.stream()
.anyMatch("banana"::equals);输出结果:
描述:检查列表中是否包含"banana"
结果值:结果为 true14. Stream 的 allMatch
业务数据:一系列字符串。
List<String> strings = Arrays.asList("apple", "banana", "cherry");函数使用:
boolean allFruits = strings.stream()
.allMatch(s -> s.startsWith("b"));输出结果:
描述:检查所有字符串是否以"b"开头
结果值:结果为 false15. Stream 的 noneMatch
业务数据:一系列字符串。
List<String> strings = Arrays.asList("apple", "banana", "cherry");函数使用:
boolean noDates = strings.stream()
.noneMatch("date"::equals);输出结果:
描述:检查列表中是否没有"date"
结果值:结果为 true16. Stream 的 findAny
业务数据:一系列数字。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);函数使用:
java
Optional<Integer> anyNumber = numbers.stream()
.findAny()输出结果:
描述:找出任意一个数字
结果值:可能的结果为 1(或其他数字,取决于实现)17. Stream 的 findFirst
业务数据:一系列字符串。
List<String> strings = Arrays.asList("apple", "banana", "cherry");函数使用:
Optional<String> firstString = strings.stream()
.findFirst();输出结果:
描述:找出第一个字符串
结果值:可能的结果为 "apple"(或其他字符串,取决于实现)18. Stream 的 peek
业务数据:一系列字符串。
List<String> strings = Arrays.asList("apple", "banana", "cherry");函数使用:
java
strings.stream()
.peek(System.out::println)
.collect(Collectors.toList());输出结果:
描述:打印每个字符串并收集到列表
结果值:
apple
banana
cherry
["apple", "banana", "cherry"]19. Stream 的 toArray
业务数据:一系列字符串。
List<String> strings = Arrays.asList("apple", "banana", "cherry");函数使用:
String[] stringArray = strings.stream()
.toArray(String[]::new);输出结果:
描述:将字符串流转换为数组
结果值:字符串数组 ["apple", "banana", "cherry"]20. Stream 的 boxed
业务数据:一系列整数。
IntStream intStream = IntStream.of(1, 2, 3, 4, 5);函数使用:
Stream<Integer> integerStream = intStream.boxed();输出结果:
复制
描述:将基本类型流转换为对象流
结果值:Stream of Integers [1, 2, 3, 4, 5]20. Stream 完整案例
业务背景
需要处理以下需求:
- 计算总销售额。
- 找出最昂贵的订单。
- 筛选出金额超过1000的订单。
- 获取所有不重复的客户名称。
- 计算已交付订单的数量。
- 计算订单的平均金额。
- 使用并行流提高处理速度。
业务数据
List<Order> orders = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
orders.add(new Order("Customer" + i % 100, i % 10000 + 1, Math.random() * 5000 + 500));
}在这个模拟数据中,我们生成了100万个订单,每个订单有客户名称、订单ID和随机生成的金额(500到5500)。
函数使用
double totalSales = orders.stream()
.mapToDouble(Order::getAmount)
.sum();
Optional<Order> mostExpensiveOrder = orders.stream()
.max(Order::compareByAmount);
List<Order> ordersOverThreshold = orders.stream()
.filter(order -> order.getAmount() > 1000)
.collect(Collectors.toList());
Set<String> uniqueCustomerNames = orders.stream()
.map(Order::getCustomerName)
.collect(Collectors.toSet());
long orderCount = orders.stream()
.filter(Order::isDelivered)
.count();
double averageOrderAmount = orders.stream()
.mapToDouble(Order::getAmount)
.average()
.orElse(0.0);
double parallelTotalSales = orders.parallelStream()
.mapToDouble(Order::getAmount)
.sum();输出结果
- 总销售额:
totalSales表示所有订单的总金额。 - 最昂贵的订单:
mostExpensiveOrder包含金额最高的订单信息。 - 金额超过1000的订单列表:
ordersOverThreshold包含所有金额超过1000的订单。 - 不重复的客户名称集合:
uniqueCustomerNames包含所有不同的客户名称。 - 已交付订单的数量:
orderCount表示已交付的订单数。 - 订单的平均金额:
averageOrderAmount表示所有订单金额的平均值。 - 并行流处理的总销售额:
parallelTotalSales使用并行流计算的总销售额,可以提高处理速度。