使用Java Stream实现
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
class Order {
private Long orderId;
private LocalDateTime orderTime;
private double orderAmount;
private String orderStatus;
public Order(Long orderId, LocalDateTime orderTime, double orderAmount, String orderStatus) {
this.orderId = orderId;
this.orderTime = orderTime;
this.orderAmount = orderAmount;
this.orderStatus = orderStatus;
}
public Long getOrderId() {
return orderId;
}
public LocalDateTime getOrderTime() {
return orderTime;
}
public double getOrderAmount() {
return orderAmount;
}
public String getOrderStatus() {
return orderStatus;
}
}
public class OrderAnalysis {
public static void main(String[] args) {
List<Order> orders = new ArrayList<>();
// 假设填充了订单数据
LocalDateTime oneWeekAgo = LocalDateTime.now().minus(1, ChronoUnit.WEEKS);
// 筛选最近一周内下单且订单状态为已完成的订单
Map<String, Long> amountGroupCount = orders.stream()
.filter(order -> order.getOrderTime().isAfter(oneWeekAgo) && "已完成".equals(order.getOrderStatus()))
.collect(Collectors.groupingBy(
order -> {
if (order.getOrderAmount() <= 100) {
return "0 - 100";
} else if (order.getOrderAmount() <= 200) {
return "101 - 200";
} else {
return "201及以上";
}
},
Collectors.counting()
));
OptionalDouble averageOver500 = orders.stream()
.filter(order -> order.getOrderTime().isAfter(oneWeekAgo) && "已完成".equals(order.getOrderStatus()) && order.getOrderAmount() > 500)
.mapToDouble(Order::getOrderAmount)
.average();
System.out.println("金额区间订单数量: " + amountGroupCount);
averageOver500.ifPresent(avg -> System.out.println("金额大于500的订单平均金额: " + avg));
}
}
使用传统foreach实现
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
class Order {
private Long orderId;
private LocalDateTime orderTime;
private double orderAmount;
private String orderStatus;
public Order(Long orderId, LocalDateTime orderTime, double orderAmount, String orderStatus) {
this.orderId = orderId;
this.orderTime = orderTime;
this.orderAmount = orderAmount;
this.orderStatus = orderStatus;
}
public Long getOrderId() {
return orderId;
}
public LocalDateTime getOrderTime() {
return orderTime;
}
public double getOrderAmount() {
return orderAmount;
}
public String getOrderStatus() {
return orderStatus;
}
}
public class OrderAnalysis {
public static void main(String[] args) {
List<Order> orders = new ArrayList<>();
// 假设填充了订单数据
LocalDateTime oneWeekAgo = LocalDateTime.now().minus(1, ChronoUnit.WEEKS);
Map<String, Long> amountGroupCount = new HashMap<>();
long countOver500 = 0;
double totalOver500 = 0;
for (Order order : orders) {
if (order.getOrderTime().isAfter(oneWeekAgo) && "已完成".equals(order.getOrderStatus())) {
String group = "";
if (order.getOrderAmount() <= 100) {
group = "0 - 100";
} else if (order.getOrderAmount() <= 200) {
group = "101 - 200";
} else {
group = "201及以上";
}
amountGroupCount.put(group, amountGroupCount.getOrDefault(group, 0L) + 1);
if (order.getOrderAmount() > 500) {
countOver500++;
totalOver500 += order.getOrderAmount();
}
}
}
double averageOver500 = countOver500 == 0? 0 : totalOver500 / countOver500;
System.out.println("金额区间订单数量: " + amountGroupCount);
if (countOver500 > 0) {
System.out.println("金额大于500的订单平均金额: " + averageOver500);
}
}
}
Java Stream在简洁性和性能优化上的优势
- 简洁性:
- Java Stream使用函数式编程风格,通过链式调用的方式,将复杂的操作(如筛选、分组、统计等)组合在一起,代码更加简洁明了。相比之下,传统foreach循环需要更多的变量声明、条件判断和累加逻辑,代码冗长。例如,在Stream中,筛选、分组和统计可以在一个链式调用中完成,而foreach循环需要在循环体中分别实现这些逻辑。
- 性能优化:
- 并行处理:Java Stream支持并行流,能够充分利用多核CPU的优势,将数据分成多个部分并行处理,大大提高处理海量数据的效率。而传统foreach循环是顺序执行的,在多核环境下无法自动利用多核资源。例如,在处理大规模订单数据时,并行流可以将订单数据分成多个子集,在不同的CPU核心上同时进行筛选、分组等操作,从而加快处理速度。
- 延迟计算:Stream操作分为中间操作(如filter、map等)和终端操作(如collect、count等)。中间操作是延迟执行的,只有在终端操作调用时才会真正执行整个流的处理。这可以避免不必要的计算,特别是在处理大数据流时,如果在中间操作过程中提前判断出不需要继续处理某些数据,就可以减少计算量。例如,如果在筛选订单时,提前判断出某个订单不符合条件,就不会再对该订单进行后续的分组和统计操作。
Java Stream潜在的问题
- 调试困难:Stream的链式调用使得代码逻辑集中在一行或少数几行代码中,调试时难以定位问题。因为Stream操作在底层是通过迭代器等方式实现的,错误信息可能不够直观,不如传统foreach循环那样容易在循环体中添加调试语句来定位问题。
- 内存消耗:在并行流处理时,如果数据量非常大,可能会因为创建多个并行处理的线程和中间数据结构而导致内存消耗过大。特别是在处理大数据集时,并行流可能会创建大量的临时数据结构来存储中间结果,从而增加内存压力,甚至导致内存溢出错误。
- 性能问题:虽然并行流在理论上可以提高性能,但在某些情况下,并行流的开销(如线程创建、数据划分和合并等)可能会超过其带来的性能提升。例如,在数据量较小或者操作本身比较简单时,并行流的额外开销可能会使得性能反而不如顺序流或传统foreach循环。此外,如果数据之间存在复杂的依赖关系,并行流的并行处理可能会导致结果错误,因为并行流是无序处理数据的,需要特别注意数据的一致性和依赖性问题。