Java 8 新特性详细教程

Java 8 新特性详细教程

Java 8 是 Java 语言中的一个重要版本,它引入了许多革命性的功能,比如 Lambda 表达式、Stream API、Optional 类和全新的日期时间 API 等。这些功能显著提升了 Java 开发效率和代码的可读性。本教程将对这些新特性进行深入讲解,并提供丰富的示例代码。


目录

  1. [Lambda表达式](#1-Lambda 表达式)
  2. 函数式接口
  3. 方法引用
  4. [Stream API](#4-Stream API)
  5. [Optional 类](#5-Optional 类)
  6. [新的日期时间 API](#6-新的日期时间 API)
  7. [Collectors 工具类](#7-Collectors 工具类)
  8. [并行 Stream](#8-并行 Stream)
  9. 其他重要改进

1. Lambda 表达式

1.1 什么是 Lambda 表达式?

Lambda 表达式是 Java 8 中引入的一种语法糖,用来替代匿名内部类,主要用于简化函数式接口的实现。通过 Lambda 表达式,代码可以更加简洁和优雅。

1.2 语法结构

Lambda 表达式的基本语法如下:

(parameters) -> expression

或者包含多条语句时:

(parameters) -> { statements; }
  • 参数:指定传递给方法的参数,可以没有参数、单个参数或多个参数。
  • 箭头 ->:表示将输入的参数传递到表达式或代码块。
  • 表达式或代码块:实现逻辑。

1.3 使用场景

  • 代替匿名内部类:适用于只有一个抽象方法的接口(即函数式接口)。
  • 简化集合操作:如 forEach 遍历。

1.4 示例

传统匿名类实现:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(new Consumer<String>() {
    @Override
    public void accept(String name) {
        System.out.println("Hello, " + name);
    }
});

Lambda 表达式实现:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println("Hello, " + name));

1.5 Lambda 表达式的详细示例

1.5.1 单参数的 Lambda 表达式
names.forEach(name -> System.out.println(name));
1.5.2 多参数的 Lambda 表达式
Comparator<String> comparator = (a, b) -> a.compareToIgnoreCase(b);
List<String> sortedNames = names.stream()
                                .sorted(comparator)
                                .collect(Collectors.toList());
1.5.3 无参数的 Lambda 表达式
Runnable runnable = () -> System.out.println("Lambda running!");
new Thread(runnable).start();

1.6 省略规则

  1. 参数类型可以省略,Java 会自动推导。
  2. 单个参数时,可以省略括号。
  3. 单条语句时,可以省略大括号和 return 关键字。

示例:

names.forEach(name -> System.out.println(name)); // 等价于 name -> { System.out.println(name); }

2. 函数式接口

2.1 什么是函数式接口?

函数式接口是一个只有一个抽象方法的接口。这种接口可以直接使用 Lambda 表达式进行实例化。

常见函数式接口:

  • Consumer<T>:接受一个参数,无返回值。
  • Function<T, R>:接受一个参数,返回一个结果。
  • Predicate<T>:接受一个参数,返回布尔值。
  • Supplier<T>:无参数,返回一个结果。

2.2 自定义函数式接口

@FunctionalInterface
interface Greeting {
    void sayHello(String name);
}

使用示例:

Greeting greeting = name -> System.out.println("Hello, " + name);
greeting.sayHello("Alice");

注意:

  1. 函数式接口可以包含 defaultstatic 方法。
  2. 添加 @FunctionalInterface 注解可以避免误添加多余的抽象方法。

3. 方法引用

方法引用是 Lambda 表达式的一种简洁写法,直接引用已有的方法。使用 :: 符号表示方法引用。

3.1 类型

  1. 静态方法引用ClassName::methodName
  2. 实例方法引用instance::methodName
  3. 构造方法引用ClassName::new

3.2 示例

3.2.1 静态方法引用
names.forEach(System.out::println); // 等价于 name -> System.out.println(name)
3.2.2 实例方法引用
List<String> sortedNames = names.stream()
                                .sorted(String::compareToIgnoreCase)
                                .collect(Collectors.toList());
3.2.3 构造方法引用
Supplier<List<String>> listSupplier = ArrayList::new;
List<String> newList = listSupplier.get();

4. Stream API

4.1 什么是 Stream?

Stream 是 Java 8 中新增的工具类,专为处理集合数据而设计。它支持函数式编程风格,提供强大的数据操作能力。


4.2 Stream 的核心操作

  1. 创建 Stream:通过 stream() 方法创建流。
  2. 中间操作
    • filter:过滤数据。
    • map:对数据进行映射。
    • sorted:对数据排序。
  3. 终止操作
    • forEach:遍历数据。
    • collect:将结果收集为集合。

4.3 示例

4.3.1 基本使用
List<String> filteredNames = names.stream()
                                  .filter(name -> name.startsWith("A"))
                                  .collect(Collectors.toList());
4.3.2 复杂操作
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squaredNumbers = numbers.stream()
                                       .filter(n -> n % 2 == 0)
                                       .map(n -> n * n)
                                       .collect(Collectors.toList());
System.out.println(squaredNumbers); // 输出: [4, 16]

5. Optional 类

5.1 为什么需要 Optional?

在 Java 中,null 是引发空指针异常的主要原因。Optional 提供了一种优雅的方式来处理可能为空的值。


5.2 常用方法

  1. 创建 Optional

    • Optional.of(value):创建包含非空值的 Optional。
    • Optional.ofNullable(value):允许空值。
    • Optional.empty():创建空的 Optional。
  2. 处理值

    • isPresent():检查值是否存在。
    • get():获取值(不推荐直接使用)。
    • orElse(defaultValue):为空时返回默认值。
    • orElseGet(supplier):为空时动态生成默认值。
    • map():对值进行操作。

5.3 示例

5.3.1 创建和检查值
Optional<String> optional = Optional.ofNullable("Hello");
if (optional.isPresent()) {
    System.out.println(optional.get());
}
5.3.2 使用 map 转换值
Optional<String> optional = Optional.of("hello");
optional.map(String::toUpperCase).ifPresent(System.out::println);
5.3.3 默认值
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElse("Default Value"));

6. 新的日期时间 API

6.1 简介

Java 8 提供了全新的日期时间 API,用来替代旧的 java.util.DateCalendar,设计更合理,使用更直观。

6.2 常用类

  1. LocalDate:仅表示日期。
  2. LocalTime:仅表示时间。
  3. LocalDateTime:同时表示日期和时间。

6.3 示例

6.3.1 获取当前日期时间
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();
System.out.println("Date: " + date);
System.out.println("Time: " + time);
System.out.println("DateTime: " + dateTime);
6.3.2 日期运算
LocalDate date = LocalDate.of(2024, 11, 12);
LocalDate nextWeek = date.plusWeeks(1);
System.out.println("Next Week: " + nextWeek);

7. Collectors 工具类

7.1 什么是 Collectors?

Collectors 是一个工具类,提供了许多静态方法,用于汇总和转换 Stream 中的数据,常见功能包括:

  • 转换为集合(toListtoSet 等)
  • 数据分组(groupingBy
  • 数据分区(partitioningBy
  • 字符串拼接(joining

7.2 常用方法

7.2.1 转换为集合
import java.util.*;
import java.util.stream.Collectors;

public class CollectorsExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Alice");

        // 转换为 Set,去重
        Set<String> uniqueNames = names.stream()
                                       .collect(Collectors.toSet());
        System.out.println("Unique Names: " + uniqueNames);
    }
}
7.2.2 数据分组
import java.util.*;
import java.util.stream.Collectors;

public class GroupingExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Daniel");

        // 按名字首字母分组
        Map<Character, List<String>> groupedByFirstLetter = names.stream()
                .collect(Collectors.groupingBy(name -> name.charAt(0)));
        System.out.println(groupedByFirstLetter);
    }
}
7.2.3 数据分区
import java.util.*;
import java.util.stream.Collectors;

public class PartitioningExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

        // 分区为奇数和偶数
        Map<Boolean, List<Integer>> partitioned = numbers.stream()
                .collect(Collectors.partitioningBy(n -> n % 2 == 0));
        System.out.println(partitioned);
    }
}
7.2.4 字符串拼接
import java.util.*;
import java.util.stream.Collectors;

public class JoiningExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // 拼接为逗号分隔的字符串
        String result = names.stream()
                             .collect(Collectors.joining(", "));
        System.out.println("Joined String: " + result);
    }
}

8. 并行 Stream

8.1 什么是并行 Stream?

并行 Stream 是 Java 8 中为流操作引入的多线程处理能力,它能充分利用多核处理器,提高数据处理速度。


8.2 并行和串行的区别

  • 串行流(Sequential Stream):流中的操作按顺序执行,单线程处理。
  • 并行流(Parallel Stream):流中的操作被分成多个线程并发执行。

8.3 示例

8.3.1 串行流
import java.util.stream.IntStream;

public class SequentialStreamExample {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        // 使用串行流计算 1 到 1,000,000 的偶数个数
        long count = IntStream.range(1, 1_000_001)
                              .filter(n -> n % 2 == 0)
                              .count();

        long end = System.currentTimeMillis();
        System.out.println("Count: " + count + ", Time: " + (end - start) + " ms");
    }
}
8.3.2 并行流
import java.util.stream.IntStream;

public class ParallelStreamExample {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        // 使用并行流计算 1 到 1,000,000 的偶数个数
        long count = IntStream.range(1, 1_000_001)
                              .parallel()
                              .filter(n -> n % 2 == 0)
                              .count();

        long end = System.currentTimeMillis();
        System.out.println("Count: " + count + ", Time: " + (end - start) + " ms");
    }
}

注意:

  1. 并行流适合计算密集型任务,对于 I/O 密集型任务可能不如串行流。
  2. 不要在并行流中操作共享变量,否则可能引发线程安全问题。

9. 其他重要改进

9.1 接口中的默认方法和静态方法

Java 8 允许在接口中定义默认方法和静态方法,从而为接口提供更多灵活性。

默认方法

默认方法可以为接口方法提供一个默认实现,使得在扩展接口时无需修改现有实现类。

示例:

interface Vehicle {
    default void start() {
        System.out.println("Vehicle is starting");
    }
}

class Car implements Vehicle {}

public class DefaultMethodExample {
    public static void main(String[] args) {
        Vehicle car = new Car();
        car.start(); // 输出: Vehicle is starting
    }
}
静态方法

接口中的静态方法只能通过接口名调用,不能通过实现类调用。

示例:

interface Vehicle {
    static void stop() {
        System.out.println("Vehicle is stopping");
    }
}

public class StaticMethodExample {
    public static void main(String[] args) {
        Vehicle.stop(); // 输出: Vehicle is stopping
    }
}

9.2 Map 的增强操作

Java 8 为 Map 添加了许多便捷操作,比如 forEachcomputeIfAbsentmerge

forEach
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.forEach((key, value) -> System.out.println(key + ": " + value));
computeIfAbsent
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.computeIfAbsent("B", key -> 42); // 如果 "B" 不存在,则插入 42
System.out.println(map);
merge
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.merge("A", 2, Integer::sum); // 如果 "A" 存在,执行合并操作
System.out.println(map);

9.3 Base64 编码解码

Java 8 内置了 Base64 编码和解码功能,无需再引入外部库。

示例
import java.util.Base64;

public class Base64Example {
    public static void main(String[] args) {
        // 编码
        String original = "Java8 Base64";
        String encoded = Base64.getEncoder().encodeToString(original.getBytes());
        System.out.println("Encoded: " + encoded);

        // 解码
        String decoded = new String(Base64.getDecoder().decode(encoded));
        System.out.println("Decoded: " + decoded);
    }
}

Java8 新特性
Java11 新特性
Java17 新特性
Java21 新特性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愤怒的代码

如果您有受益,欢迎打赏博主😊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值