《用Java 8新特性重构代码:让项目更简洁高效》

    • 1. Lambda表达式:简化匿名内部类
      • 1.1 传统方式 vs Lambda表达式
      • 1.2 集合遍历对比
      • 1.3 事件监听器简化
    • 2. Stream API:革命性的集合操作
      • 2.1 基本Stream操作示例
      • 2.2 数值流操作
      • 2.3 分组和分区
    • 3. Optional:优雅处理null
      • 3.1 基本Optional用法
      • 3.2 Optional实践示例
    • 4. 方法引用:更简洁的Lambda
      • 4.1 四种方法引用类型
      • 4.2 方法引用实践
    • 5. 新的日期时间API
      • 5.1 基本日期操作
      • 5.2 日期格式化和解析
      • 5.3 日期时间段计算
    • 6. 默认方法和静态方法
      • 6.1 接口默认方法
      • 6.2 接口静态方法
    • 7. 并行流提高性能
      • 7.1 顺序流 vs 并行流
      • 7.2 并行流注意事项
    • 8. CompletableFuture:异步编程
      • 8.1 基本异步操作
      • 8.2 组合多个Future
    • 9. 综合重构示例
      • 9.1 传统代码示例
      • 9.2 Java 8重构版本
    • 10. 性能考虑与最佳实践
      • 10.1 Stream性能测试
      • 10.2 Java 8最佳实践
    • 11. 常见问题与解决方案
      • 11.1 调试Lambda表达式
      • 11.2 异常处理
    • 12. 总结与进一步学习
      • 12.1 Java 8特性总结表

1. Lambda表达式:简化匿名内部类

1.1 传统方式 vs Lambda表达式

// 传统方式 - 匿名内部类
Runnable oldRunnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("Running in old way");
    }
};

// Java 8 Lambda方式
Runnable newRunnable = () -> System.out.println("Running with Lambda");

1.2 集合遍历对比

List<String> languages = Arrays.asList("Java", "Python", "C++", "JavaScript");

// 传统for循环
for (String lang : languages) {
    System.out.println(lang);
}

// 使用Lambda和forEach
languages.forEach(lang -> System.out.println(lang));

// 方法引用更简洁
languages.forEach(System.out::println);

1.3 事件监听器简化

// Swing事件监听传统写法
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Button clicked!");
    }
});

// Lambda简化版
button.addActionListener(e -> System.out.println("Button clicked!"));

2. Stream API:革命性的集合操作

2.1 基本Stream操作示例

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 过滤和收集
List<String> longNames = names.stream()
    .filter(name -> name.length() > 4)
    .collect(Collectors.toList());  // [Alice, Charlie, David]

// 映射
List<Integer> nameLengths = names.stream()
    .map(String::length)
    .collect(Collectors.toList());  // [5, 3, 7, 5]

// 排序
List<String> sortedNames = names.stream()
    .sorted()
    .collect(Collectors.toList());  // [Alice, Bob, Charlie, David]

2.2 数值流操作

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// 求和
int sum = numbers.stream().reduce(0, Integer::sum);

// 求平均值
double average = numbers.stream()
    .mapToInt(Integer::intValue)
    .average()
    .orElse(0.0);

// 找出最大值
int max = numbers.stream().max(Integer::compare).orElse(0);

2.3 分组和分区

class Person {
    String name;
    int age;
    String city;
    // 构造方法、getter/setter省略
}

List<Person> people = Arrays.asList(
    new Person("Alice", 25, "New York"),
    new Person("Bob", 30, "Chicago"),
    new Person("Charlie", 25, "New York"),
    new Person("David", 30, "Chicago")
);

// 按城市分组
Map<String, List<Person>> peopleByCity = people.stream()
    .collect(Collectors.groupingBy(Person::getCity));

// 按年龄分区(25岁以下和以上)
Map<Boolean, List<Person>> partitionedPeople = people.stream()
    .collect(Collectors.partitioningBy(p -> p.getAge() > 25));

3. Optional:优雅处理null

3.1 基本Optional用法

// 传统null检查
public String getCityTraditional(Person person) {
    if (person != null) {
        Address address = person.getAddress();
        if (address != null) {
            return address.getCity();
        }
    }
    return "Unknown";
}

// 使用Optional
public String getCityWithOptional(Person person) {
    return Optional.ofNullable(person)
        .map(Person::getAddress)
        .map(Address::getCity)
        .orElse("Unknown");
}

3.2 Optional实践示例

// 从可能为null的列表中查找元素
List<String> possibleNullList = getPossibleNullList();

// 传统方式
String result = null;
if (possibleNullList != null && !possibleNullList.isEmpty()) {
    result = possibleNullList.get(0);
}

// Optional方式
String result = Optional.ofNullable(possibleNullList)
    .filter(list -> !list.isEmpty())
    .map(list -> list.get(0))
    .orElse("default");

4. 方法引用:更简洁的Lambda

4.1 四种方法引用类型

// 1. 静态方法引用
Function<String, Integer> parser = Integer::parseInt;

// 2. 实例方法引用
List<String> strings = Arrays.asList("a", "b", "c");
strings.forEach(System.out::println);

// 3. 特定对象的实例方法引用
StringComparator myComparator = new StringComparator();
strings.sort(myComparator::compare);

// 4. 构造方法引用
Supplier<List<String>> listSupplier = ArrayList::new;

4.2 方法引用实践

// 将字符串列表转换为大写
List<String> names = Arrays.asList("alice", "bob", "charlie");

// Lambda方式
List<String> upperNames = names.stream()
    .map(name -> name.toUpperCase())
    .collect(Collectors.toList());

// 方法引用方式
List<String> upperNames = names.stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());

5. 新的日期时间API

5.1 基本日期操作

// 获取当前日期
LocalDate today = LocalDate.now();

// 创建特定日期
LocalDate independenceDay = LocalDate.of(2023, Month.JULY, 4);

// 日期运算
LocalDate nextWeek = today.plusWeeks(1);
LocalDate previousMonthSameDay = today.minusMonths(1);

// 日期比较
boolean isAfter = today.isAfter(independenceDay);

5.2 日期格式化和解析

// 格式化
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = now.format(formatter);

// 解析
String dateStr = "2023-07-04 12:30:00";
LocalDateTime parsed = LocalDateTime.parse(dateStr, formatter);

5.3 日期时间段计算

// 计算两个日期之间的天数
LocalDate startDate = LocalDate.of(2023, 1, 1);
LocalDate endDate = LocalDate.of(2023, 12, 31);
long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);

// 计算年龄
LocalDate birthDate = LocalDate.of(1990, 5, 15);
long age = ChronoUnit.YEARS.between(birthDate, LocalDate.now());

6. 默认方法和静态方法

6.1 接口默认方法

interface Vehicle {
    String getBrand();
    
    default String turnAlarmOn() {
        return "Turning the vehicle alarm on.";
    }
    
    default String turnAlarmOff() {
        return "Turning the vehicle alarm off.";
    }
}

class Car implements Vehicle {
    @Override
    public String getBrand() {
        return "BMW";
    }
}

// 使用
Vehicle car = new Car();
System.out.println(car.getBrand());      // BMW
System.out.println(car.turnAlarmOn());   // Turning the vehicle alarm on.

6.2 接口静态方法

interface MathOperations {
    static int add(int a, int b) {
        return a + b;
    }
    
    static int subtract(int a, int b) {
        return a - b;
    }
}

// 使用
int sum = MathOperations.add(5, 3);      // 8
int difference = MathOperations.subtract(5, 3);  // 2

7. 并行流提高性能

7.1 顺序流 vs 并行流

List<Integer> numbers = IntStream.rangeClosed(1, 1_000_000)
    .boxed()
    .collect(Collectors.toList());

// 顺序流
long start = System.currentTimeMillis();
long count = numbers.stream()
    .filter(n -> n % 2 == 0)
    .count();
long sequentialTime = System.currentTimeMillis() - start;

// 并行流
start = System.currentTimeMillis();
count = numbers.parallelStream()
    .filter(n -> n % 2 == 0)
    .count();
long parallelTime = System.currentTimeMillis() - start;

System.out.println("Sequential time: " + sequentialTime + "ms");
System.out.println("Parallel time: " + parallelTime + "ms");

7.2 并行流注意事项

// 错误示例 - 共享可变状态
int[] sharedCounter = new int[1];
IntStream.range(0, 10_000).parallel()
    .forEach(i -> sharedCounter[0]++);  // 竞态条件!

// 正确方式 - 使用原子变量
AtomicInteger safeCounter = new AtomicInteger(0);
IntStream.range(0, 10_000).parallel()
    .forEach(i -> safeCounter.incrementAndGet());

8. CompletableFuture:异步编程

8.1 基本异步操作

// 简单的异步计算
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        throw new IllegalStateException(e);
    }
    return "Result of the asynchronous computation";
});

// 阻塞获取结果
String result = future.get();
System.out.println(result);

8.2 组合多个Future

// 模拟远程服务调用
CompletableFuture<String> getUser = CompletableFuture.supplyAsync(() -> {
    // 模拟延迟
    try { Thread.sleep(500); } catch (InterruptedException e) {}
    return "User123";
});

CompletableFuture<String> getOrder = CompletableFuture.supplyAsync(() -> {
    try { Thread.sleep(800); } catch (InterruptedException e) {}
    return "Order456";
});

// 组合两个独立的任务
CompletableFuture<String> combined = getUser.thenCombine(getOrder, 
    (user, order) -> "User " + user + " has order " + order);

System.out.println(combined.get());  // User User123 has order Order456

9. 综合重构示例

9.1 传统代码示例

public class OrderProcessor {
    public List<Order> processOrders(List<Order> orders) {
        List<Order> validOrders = new ArrayList<>();
        
        // 过滤无效订单
        for (Order order : orders) {
            if (order.isValid() && order.getAmount() > 0) {
                validOrders.add(order);
            }
        }
        
        // 按金额排序
        Collections.sort(validOrders, new Comparator<Order>() {
            @Override
            public int compare(Order o1, Order o2) {
                return Double.compare(o1.getAmount(), o2.getAmount());
            }
        });
        
        // 计算总金额
        double total = 0;
        for (Order order : validOrders) {
            total += order.getAmount();
        }
        
        System.out.println("Total amount: " + total);
        
        return validOrders;
    }
}

9.2 Java 8重构版本

public class OrderProcessor {
    public List<Order> processOrders(List<Order> orders) {
        return orders.stream()
            .filter(Order::isValid)
            .filter(order -> order.getAmount() > 0)
            .sorted(Comparator.comparingDouble(Order::getAmount))
            .peek(order -> System.out.println("Processing order: " + order.getId()))
            .collect(Collectors.toList());
    }
    
    public double calculateTotal(List<Order> orders) {
        return orders.stream()
            .mapToDouble(Order::getAmount)
            .sum();
    }
}

10. 性能考虑与最佳实践

10.1 Stream性能测试

// 测试不同操作方式的性能
public class PerformanceTest {
    private static final int SIZE = 10_000_000;
    private static List<Integer> numbers = IntStream.range(0, SIZE)
        .boxed()
        .collect(Collectors.toList());
    
    public static void main(String[] args) {
        // 传统for循环
        long start = System.currentTimeMillis();
        int sum = 0;
        for (int n : numbers) {
            sum += n;
        }
        long time = System.currentTimeMillis() - start;
        System.out.println("For loop sum: " + sum + ", time: " + time + "ms");
        
        // 顺序流
        start = System.currentTimeMillis();
        sum = numbers.stream().mapToInt(Integer::intValue).sum();
        time = System.currentTimeMillis() - start;
        System.out.println("Sequential stream sum: " + sum + ", time: " + time + "ms");
        
        // 并行流
        start = System.currentTimeMillis();
        sum = numbers.parallelStream().mapToInt(Integer::intValue).sum();
        time = System.currentTimeMillis() - start;
        System.out.println("Parallel stream sum: " + sum + ", time: " + time + "ms");
    }
}

10.2 Java 8最佳实践

// 1. 优先使用方法引用而不是Lambda
list.forEach(x -> System.out.println(x));  // 不好
list.forEach(System.out::println);         // 好

// 2. 避免在Lambda中修改外部状态
List<String> result = new ArrayList<>();
list.forEach(s -> result.add(s.toUpperCase()));  // 不好
List<String> result = list.stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());               // 好

// 3. 谨慎使用并行流
list.parallelStream()...  // 只在数据量大且操作耗时的情况下使用

// 4. 优先使用新的日期时间API
Date oldDate = new Date();                  // 不好
LocalDate newDate = LocalDate.now();        // 好

// 5. 合理使用Optional
Optional.ofNullable(getPossibleNullValue())  // 明确表示可能为null
    .ifPresentOrElse(
        value -> process(value),
        () -> handleNull()
    );

11. 常见问题与解决方案

11.1 调试Lambda表达式

// 调试困难的Lambda
list.stream()
    .filter(s -> {
        System.out.println("Filtering: " + s);  // 临时调试语句
        return s.length() > 3;
    })
    .map(s -> {
        System.out.println("Mapping: " + s);  // 临时调试语句
        return s.toUpperCase();
    })
    .forEach(System.out::println);

// 更好的方式 - 使用peek
list.stream()
    .peek(s -> System.out.println("Before filter: " + s))
    .filter(s -> s.length() > 3)
    .peek(s -> System.out.println("After filter: " + s))
    .map(String::toUpperCase)
    .forEach(System.out::println);

11.2 异常处理

// Lambda中的异常处理
List<String> urls = Arrays.asList("http://example.com", "http://invalid.url");

// 不好的方式 - 在Lambda中直接try-catch
urls.stream()
    .map(url -> {
        try {
            return new URL(url);
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return null;
        }
    })
    .filter(Objects::nonNull)
    .forEach(System.out::println);

// 好的方式 - 提取方法或使用工具类
urls.stream()
    .map(ThrowingFunction.unchecked(URL::new))
    .forEach(System.out::println);

// ThrowingFunction工具类
@FunctionalInterface
public interface ThrowingFunction<T, R, E extends Exception> {
    R apply(T t) throws E;
    
    static <T, R> Function<T, R> unchecked(ThrowingFunction<T, R, Exception> f) {
        return t -> {
            try {
                return f.apply(t);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        };
    }
}

12. 总结与进一步学习

12.1 Java 8特性总结表

特性 主要用途 示例
Lambda表达式 简化匿名内部类 () -> System.out.println("Hi")
Stream API 集合处理流水线 list.stream().filter().map().collect()
Optional 避免NullPointerException Optional.ofNullable(value).orElse(default)
方法引用 简化Lambda String::toUpperCase
新日期API 更好的日期处理 LocalDate.now().plusDays(1)
默认方法 接口演化 interface A { default void foo() {} }
并行流 并行处理集合 list.parallelStream().forEach()
CompletableFuture 异步编程 CompletableFuture.supplyAsync(() -> "result")

你可能感兴趣的:(Java8新特性,java,重构,开发语言)