JDK8 新特性全面总结(5大最实用新特性及其应用)

JDK20 都来了,你还在用 JDK8 吗?

JDK8 引入了很多实用的新特性,JDK8 的这些新特性,极大地改进了Java 的开发效率和灵活性。

2014 -2023 年期间,Java 从 JDK8 到 JDK20 一共发布了13个版本,但 JDK8 依然是当下最受欢迎的,并且稳如泰山。

在面试中,面试官也特别喜欢问一些 JDK8 新特性的问题。

附图:skyn 发布的《JVM生态报告》

本文主要深入 JDK8 最具有代表性的5大新特性(面试高频必问),包括它们的用法及应用场景详解。

  • Lambda 表达式和方法引用
  • 接口中的默认方法和静态方法
  • 函数式接口
  • Stream API
  • 时间日期API

1. Lambda表达式和方法引用

Lambda 表达式是 JDK8 中引入的一种新语法,也是一种匿名函数,它可以作为参数传递给其他方法或存储在变量中,让代码编写更加简洁、可读性高。

Lambda 表达式的语法很简洁,由一个参数列表、一个箭头和一个函数体组成。

例如:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, (String a, String b) -> a.compareTo(b));

示例使用 Lambda 表达式作为 Collections.sort 方法的第二个参数。Lambda 表达式的函数体是 a.compareTo(b),它实现了比较两个字符串的逻辑。

方法引用则是对 Lambda 表达式的一种简化形式。

方法引用允许引用已有的方法作为 Lambda 表达式的函数体。例如:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, String::compareTo);

这段代码与之前的代码是差不多的效果,但是使用了方法引用来代替 Lambda 表达式。

String::compareTo 是一个方法引用,它引用了 String 类中的 compareTo 方法。

2. 接口中的默认方法和静态方法

在 JDK8 之前,接口中只能声明抽象方法。

JDK8 引入了默认方法和静态方法之后,可以更加便捷高效在接口中添加新的功能。

默认方法:

默认方法是一种在接口中有默认实现的方法,能够在不改变现有实现的情况下添加新功能,默认方法可以通过关键字 default 来声明。

例如:

public interface Vehicle {
    default void move() {
        System.out.println("Vehicle is moving");
    }
}

这个接口声明了一个默认方法 move(),它打印出“Vehicle is moving”这句话。如果某个类实现了这个接口但没有重写 move() 方法,那么默认实现就会被使用。

默认方法可以用于向现有接口添加新的功能,而不会影响现有的实现。如果我们需要在现有接口上添加新功能,这种功能就非常有用了。

静态方法:

静态方法是一种在接口中声明的静态方法,能够通过接口名直接调用,静态方法可以通过关键字 static 来声明。

例如:

public interface Vehicle {
    static void honk() {
        System.out.println("Vehicle is honking");
    }
}

这个接口声明了一个静态方法 honk(),它打印出“Vehicle is honking”这句话。

在调用这个方法时,可以使用接口名来调用:

Vehicle.honk();

静态方法可以用于在接口中声明一些通用的方法,这些方法可以被接口的所有实现类所共享。

3. 函数式接口

在 Java 8 中,Java 内置了很多函数式接口。

最常用的函数式接口:

  • Predicate<T>:判断给定输入值是否符合条件,返回一个布尔值。
  • Function<T, R>:将输入类型 T 的对象转换为输出类型 R 的对象。
  • Supplier<T>:生成给定类型 T 的对象。
  • Consumer<T>:表示接受单个输入参数,并且不返回任何结果的操作。

函数式接口是只有一个抽象方法的接口,它可以被 Lambda 表达式所赋值,在任何需要函数式编程的场景中使用。

我们通常使用函数式接口来实现复杂的逻辑,例如:多线程编程、事件驱动编程和响应式编程等场景。

import java.util.function.Predicate;

public class Example {
  public static void main(String[] args) {
    Predicate<String> predicate = (s) -> s.length() > 0;

    System.out.println(predicate.test("foo"));              // true
    System.out.println(predicate.negate().test("foo"));     // false

    Predicate<String> isEmpty = String::isEmpty;
    System.out.println(isEmpty.test(""));                   // true
    System.out.println(isEmpty.negate().test(""));          // false
  }
}

在这个例子中:

使用了 Predicate 接口,Lambda 表达式 (s) -> s.length() > 0 作为 Predicate 的实现,用于判断字符串是否为空。

展示了如何使用 negate() 方法来返回 Predicate 实例的逆。

使用了方法引用 String::isEmpty,这是一个函数式接口的实现,表示一个字符串是否为空。

4. Stream API

Java 对函数式编程的重视程度,看看 JDK8 加入函数式编程扩充多少功能就明白了。

JDK8 引入函数式编程,主要原因:

  • 使用函数式编程写出的代码简洁、可读性高,使用 stream 接口,让你从此告别 for 循环。
  • 使用函数式编程编写并行程序非常简单,只需要调用一下 parallel() 方法就搞定了。

说到这里,就不得不提 Stream,也就是 Java 函数式编程的主角。

Stream API 是一种基于流的编程模型,可以简化集合、数组等数据处理的操作,提高数据处理的效率。它包含了筛选、映射、排序等多种操作,这些操作可以进行链式调用,最终返回一个结果。

Stream API 的应用场景非常广泛,特别是在大数据处理方面。

Stream API 的使用方法:

import java.util.Arrays;
import java.util.List;

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        int sum = numbers.stream() // 创建Stream对象
                .filter(n -> n % 2 == 0) // 筛选出偶数
                .mapToInt(n -> n * 2) // 将每个元素乘以2
                .sum(); // 对结果进行求和
        System.out.println(sum); // 输出结果20
    }
}

这个示例中:

我们首先创建了一个包含 10 个整数的 List 对象 numbers,再通过 numbers.stream() 方法创建了一个Stream对象,并进行了filter()、mapToInt()等一系列的中间操作,这些操作会返回一个新的 Stream 对象。

最终,我们调用了 sum() 方法对结果进行求和,得到了结果 20 。

5. 时间日期API

在 JDK8 之前,处理时间日期 API 非常不方便。

JDK8 中引入了新的时间日期 API ,提供了更加简洁、易用和安全的方式来处理日期。

新的时间日期 API 包含了多种类和接口,例如:LocalDate、LocalTime、LocalDateTime 等。

import java.time.LocalDate;
import java.time.Month;

public class DateDemo {
    public static void main(String[] args) {
        // 创建LocalDate对象
        LocalDate date = LocalDate.of(2022, Month.MAY, 1);
        System

5.1 LocalDate、LocalTime 及 LocalDateTime

新的时间日期 API 引入了一些新的类:

  • LocalDate 用于表示日期
  • LocalTime 用于表示时间
  • LocalDateTime 同时表示日期和时间

这些类的实例可以通过静态工厂方法来创建。

例如:要创建当前日期的实例,可以使用 LocalDate.now() 方法,而要创建指定日期的实例,可以使用 LocalDate.of() 方法。

// 创建当前日期的实例
LocalDate today = LocalDate.now();

// 创建指定日期的实例
LocalDate date = LocalDate.of(2023, 4, 25);

5.2 Instant

Instant 是用于表示时间戳的类,主要用于计算两个时间点之间的时间间隔,它可以精确到纳秒级别。

Instant 类同样也提供了静态工厂方法来创建实例。

例如:

创建当前时间的实例,使用 Instant.now() 方法。

// 创建当前时间的实例
Instant now = Instant.now();

创建指定时间的实例,使用 Instant.ofEpochSecond() 方法。

// 创建指定时间的实例 
Instant instant = Instant.ofEpochSecond(1619289680);

5.3 Duration 和 Period

Duration 表示两个时间点之间的时间间隔,Period 表示两个日期之间的时间间隔,这两个类同样也提供了静态工厂方法来创建实例。

例如:

创建一个持续 1 小时的 Duration 实例,使用 Duration.ofHours() 方法。

// 创建一个持续1小时的Duration实例
Duration duration = Duration.ofHours(1);

创建一个持续3天的Period实例,可以使用Period.ofDays()方法。

// 
创建一个持续3天的Period实例 Period period = Period.ofDays(3);

5.4 DateTimeFormatter

DateTimeFormatter 是将日期时间对象格式化为字符串的类,它支持各种日期时间格式,可以自定义格式。

例如:将当前日期格式化为"yyyy-MM-dd"格式的字符串

// 将当前日期格式化为"yyyy-MM-dd"格式的字符串
String formattedDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

5.5 时区支持

JDK8 中,新的时间日期 API,提供了更加简洁、易用和安全的方式来处理日期。

新的时间日期 API 提供了对时区的支持,引入了 ZoneId 和 ZoneOffset 类来表示时区信息,并且提供了静态工厂方法来创建实例。

例如:使用ZoneId.of()方法,来创建一个表示东京时区。

// 创建一个表示东京时区的实例
ZoneId tokyoZone = ZoneId.of("Asia/Tokyo");

总结

以上,是 JDK8 最具价值的 5 个新特性的全部介绍。

关于 JDK 版本选择,宝妹儿个人的看法是:将实用性、稳定性放在第一位。

IT 江湖上曾经流传的一句老话:一个功能只要能正常工作,如非必要就不要动它。

谢谢关注 Java面试题宝,我是爱分享的程序员宝妹儿

如果觉得不错,请一键三连支持下,奉上我最新整理的 JDK8 面试题及答案,可以参考学习备面、复盘本篇知识,都是互联网中大厂面试最爱问、也很重要的知识点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值