第十章:Java 8新特性


10.1 Lambda表达式与函数式编程

1. 基本概念

  • 函数式编程思想:将行为作为参数传递
  • 核心语法
    (parameters) -> expression
    (parameters) -> { statements; }
    

2. 函数式接口

  • 定义:仅包含一个抽象方法的接口
  • 常用内置接口
    • @FunctionalInterface
    • Function<T,R>:输入T输出R
    • Predicate<T>:布尔判断
    • Consumer<T>:消费型操作
    • Supplier<T>:提供型操作
    • BiFunction<T,U,R>:双参数函数
// 示例:函数式接口定义与使用
@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}

public class LambdaDemo {
    public static void main(String[] args) {
        // 传统匿名内部类
        Calculator add = new Calculator() {
            @Override
            public int calculate(int a, int b) {
                return a + b;
            }
        };

        // Lambda表达式写法
        Calculator multiply = (a, b) -> a * b;
        
        System.out.println(add.calculate(3,4));    // 7
        System.out.println(multiply.calculate(3,4)); // 12
    }
}

3. 实际应用场景

  • 集合排序

    List<String> names = Arrays.asList("Java", "Python", "Node.js");
    names.sort((a, b) -> a.length() - b.length());
    
  • 事件监听

    button.addActionListener(event -> {
        System.out.println("按钮被点击");
        logEvent(event);
    });
    
  • 线程启动

    new Thread(() -> {
        System.out.println("Lambda线程运行");
    }).start();
    

10.2 Stream API与集合操作

1. 核心概念

  • 流式处理:声明式操作集合数据
  • 操作类型
    • 中间操作:返回新Stream(可链式调用)
    • 终端操作:触发实际计算并返回结果

2. 典型操作示例

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

// 过滤+转换+聚合
String result = languages.stream()
    .filter(s -> s.length() > 5)       // 中间操作
    .map(String::toUpperCase)          // 中间操作
    .sorted()                          // 中间操作
    .reduce((a,b) -> a + ", " + b)     // 终端操作
    .orElse("无结果");

System.out.println(result);  // 输出: JAVASCRIPT, PYTHON

3. 并行流处理

// 并行计算总和(适用于大数据集)
int sum = IntStream.range(1, 1_000_000)
    .parallel()
    .sum();

4. 常用操作汇总表

操作类型 方法 描述
创建 stream()/parallelStream() 从集合创建流
中间 filter(Predicate) 过滤元素
中间 map(Function) 转换元素
中间 sorted(Comparator) 排序
中间 distinct() 去重
终端 forEach(Consumer) 遍历
终端 collect(Collector) 聚合
终端 reduce(BinaryOperator) 归约

10.3 默认方法与接口扩展

1. 默认方法语法

public interface Formula {
    double calculate(int a);
    
    // 默认方法
    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}

2. 多重继承冲突处理

interface A {
    default void log() {
        System.out.println("A");
    }
}

interface B {
    default void log() {
        System.out.println("B");
    }
}

class C implements A, B {
    public void log() {
        A.super.log();  // 显式指定调用A的实现
    }
}

3. 静态方法支持

public interface MathUtils {
    static int max(int a, int b) {
        return Math.max(a, b);
    }
}

// 调用方式
int result = MathUtils.max(10, 20);

4. 设计优势

  • 向后兼容:在接口中添加新方法不影响现有实现类
  • 代码复用:避免重复实现公共逻辑
  • 混合继承:类似其他语言的trait/mixin特性

10.4 新时间日期API(java.time包)

1. 核心类对比

类型 旧版类 Java 8新版类 特性
本地日期 Date/Calendar LocalDate 无时区
本地时间 Date/Calendar LocalTime 无时区
日期时间 Date LocalDateTime 无时区
时区日期时间 - ZonedDateTime 含时区

2. 时间操作示例

// 获取当前时间
LocalDateTime now = LocalDateTime.now();
System.out.println(now);  // 2025-10-22T14:30:45.123

// 创建指定时间
LocalDate date = LocalDate.of(2025, 10, 22);
LocalTime time = LocalTime.of(14, 30, 45);
LocalDateTime dateTime = LocalDateTime.of(date, time);

// 时间计算
LocalDateTime tomorrow = now.plusDays(1).minusHours(3);

3. 时区处理

// 获取带时区的时间
ZoneId zone = ZoneId.of("Asia/Shanghai");
ZonedDateTime zoned = ZonedDateTime.now(zone);

// 不同时区转换
ZonedDateTime newYorkTime = zoned.withZoneSameInstant(ZoneId.of("America/New_York));

4. 日期格式化

// 自定义格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String formatted = now.format(formatter);  // 2025年10月22日 14:30:45

// 解析字符串为时间
LocalDate parsedDate = LocalDate.parse("2025-10-22", DateTimeFormatter.ISO_DATE);

5. 时间间隔计算

// 计算两个日期间隔
LocalDate startDate = LocalDate.of(2025, 1, 1);
LocalDate endDate = LocalDate.of(2025, 12, 31);
Period period = Period.between(startDate, endDate);
System.out.println(period.getYears() + "年" + 
                  period.getMonths() + "个月" +
                  period.getDays() + "天");

补充说明

  1. Lambda表达式限制

    • 不能访问非final变量
    • 不能抛出比函数式接口定义范围更广的异常
  2. Stream API性能优化

    • 小数据集避免并行流(创建线程池开销大)
    • 使用unordered()操作提升乱序处理效率
  3. 时间API设计优势

    • 不可变性:所有操作返回新实例
    • 线程安全:无需额外同步
    • 更清晰的API设计:方法命名统一
  4. 迁移建议

    • 新项目应直接使用java.time包
    • 旧代码改造时注意Date与LocalDateTime的转换:
      Date date = Date.from(Instant.now());
      LocalDateTime ldt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
      

更多推荐