Java8核心特性详解

1. Java8概述

Java 8是Java语言发展史上的一个重要里程碑,于2014年3月发布。它引入了许多革命性的新特性,极大地提升了开发效率和代码可读性。本文将详细介绍Java 8的四大核心特性:

  1. Lambda表达式 - 函数式编程支持
  2. Stream API - 集合处理新方式
  3. 新日期时间API - 解决旧Date/Calendar的问题
  4. 接口默认方法 - 接口的演进能力

2. Lambda表达式

2.1 什么是Lambda表达式

Lambda表达式是Java 8中最重要的新特性之一,它允许把函数作为一个方法的参数(函数作为参数传递进方法中),使代码更加简洁紧凑。

2.2 Lambda语法

基本语法:

1
2
3
(parameters) -> expression

(parameters) -> { statements; }

2.3 Lambda示例

示例1:无参数

1
() -> System.out.println("Hello Lambda");

示例2:一个参数

1
str -> System.out.println(str);

示例3:多个参数

1
(int a, int b) -> a + b

示例4:带返回值

1
2
3
4
(String s1, String s2) -> {
System.out.println("Comparing " + s1 + " and " + s2);
return s1.compareTo(s2);
}

2.4 函数式接口

Lambda表达式需要函数式接口的支持。函数式接口是指仅包含一个抽象方法的接口。Java 8提供了@FunctionalInterface注解来标识函数式接口。

1
2
3
4
5
6
7
8
9
10
11
@FunctionalInterface
interface MyFunctionalInterface {
void execute();
}

public class Main {
public static void main(String[] args) {
MyFunctionalInterface fi = () -> System.out.println("Executing...");
fi.execute();
}
}

2.5 Java内置函数式接口

Java 8在java.util.function包中提供了许多内置函数式接口:

  • Consumer - 接受一个输入参数,无返回值
  • Supplier - 无参数,返回一个结果
  • Function<T,R> - 接受一个输入参数,返回一个结果
  • Predicate - 接受一个输入参数,返回布尔值
  • BiFunction<T,U,R> - 接受两个输入参数,返回一个结果

3. Stream API

3.1 什么是Stream

Stream是Java 8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤和映射数据等操作。

3.2 Stream特点

  1. 不是数据结构:不存储数据
  2. 不修改源数据:对Stream的操作会产生新Stream
  3. 惰性执行:中间操作是惰性的
  4. 可消费性:Stream只能被消费一次

3.3 创建Stream

从集合创建

1
2
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();

从数组创建

1
2
String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);

使用Stream.of()

1
Stream<String> stream = Stream.of("a", "b", "c");

生成无限流

1
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2);

3.4 中间操作

filter() - 过滤

1
list.stream().filter(s -> s.startsWith("a"));

map() - 映射

1
list.stream().map(String::toUpperCase);

sorted() - 排序

1
list.stream().sorted();

distinct() - 去重

1
list.stream().distinct();

limit() - 限制数量

1
list.stream().limit(10);

3.5 终止操作

forEach() - 遍历

1
list.stream().forEach(System.out::println);

collect() - 收集

1
List<String> newList = list.stream().collect(Collectors.toList());

count() - 计数

1
long count = list.stream().count();

reduce() - 归约

1
Optional<String> reduced = list.stream().reduce((s1, s2) -> s1 + "#" + s2);

anyMatch()/allMatch()/noneMatch() - 匹配

1
boolean anyStartsWithA = list.stream().anyMatch(s -> s.startsWith("a"));

3.6 并行流

1
list.parallelStream().forEach(System.out::println);

4. 新日期时间API

4.1 旧API的问题

Java 8之前的日期时间API存在以下问题:

  1. 非线程安全 - Date和Calendar不是线程安全的
  2. 设计差 - 日期和时间类没有明确区分
  3. 时区处理麻烦

4.2 新API核心类

Java 8在java.time包中提供了新的日期时间API:

  • LocalDate - 日期(年月日)
  • LocalTime - 时间(时分秒)
  • LocalDateTime - 日期时间
  • ZonedDateTime - 带时区的日期时间
  • Instant - 时间戳
  • Duration - 时间段
  • Period - 日期段
  • DateTimeFormatter - 日期时间格式化

4.3 基本使用

获取当前日期

1
LocalDate today = LocalDate.now();

创建指定日期

1
LocalDate date = LocalDate.of(2023, Month.NOVEMBER, 15);

日期运算

1
2
LocalDate nextWeek = today.plusWeeks(1);
LocalDate previousYear = today.minusYears(1);

日期比较

1
boolean isAfter = today.isAfter(date);

格式化

1
2
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formattedDate = today.format(formatter);

解析

1
LocalDate parsedDate = LocalDate.parse("2023-11-15", formatter);

5. 接口默认方法

5.1 什么是默认方法

Java 8允许在接口中定义具有实现的方法,称为默认方法,使用default关键字修饰。

5.2 默认方法示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface Vehicle {
// 抽象方法
void start();

// 默认方法
default void stop() {
System.out.println("Vehicle stopped");
}
}

class Car implements Vehicle {
@Override
public void start() {
System.out.println("Car started");
}
}

public class Main {
public static void main(String[] args) {
Car car = new Car();
car.start(); // 实现的方法
car.stop(); // 默认方法
}
}

5.3 默认方法的作用

  1. 接口演进:可以向现有接口添加新方法而不破坏现有实现
  2. 多继承:解决Java中多继承的问题
  3. 提供通用功能:为所有实现类提供默认实现

5.4 默认方法冲突

当一个类实现多个接口,且这些接口有相同的默认方法时,需要解决冲突:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface A {
default void show() {
System.out.println("A");
}
}

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

class C implements A, B {
@Override
public void show() {
A.super.show(); // 显式调用A的默认方法
}
}

6. 其他新特性

6.1 Optional类

用于避免NullPointerException:

1
2
Optional<String> optional = Optional.ofNullable(getString());
optional.ifPresent(System.out::println);

6.2 方法引用

简化Lambda表达式:

1
2
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(System.out::println);

6.3 重复注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Repeatable(Authorities.class)
@interface Authority {
String value();
}

@interface Authorities {
Authority[] value();
}

@Authority("admin")
@Authority("user")
public class User {
// ...
}

7. 总结

Java 8通过引入Lambda表达式、Stream API、新日期时间API和接口默认方法等特性,极大地提升了Java语言的表达能力和开发效率。这些特性使得Java能够更好地适应现代编程需求,特别是在函数式编程和大数据处理方面。

掌握这些核心特性,可以帮助开发者编写更简洁、更易读、更高效的Java代码。

参考资料

  1. Java 8官方文档
  2. Java 8新特性教程
  3. Java 8实战
  4. Java 8 Stream API指南