JDK8 新特性

1. Lambda 表达式

Lambda 表达式是 JDK 8 中引入的一项重要特性,它为 Java 引入了函数式编程的概念,使得代码变得更为简洁、灵活。Lambda 表达式主要用于替代匿名内部类的写法,可以将函数作为参数传递给方法,使得代码更加具有表达力。本节将详细解释 Lambda 表达式的语法和使用方法,并提供一些示例来说明其用法。

Lambda 表达式语法

Lambda 表达式的语法比较简洁,主要由以下几个部分组成:

  1. 形参列表:Lambda 表达式可以有零个或多个参数,如果没有参数,则使用空括号表示。

  2. 箭头符号 ->:箭头符号将形参列表和Lambda 表达式的主体分开。

  3. Lambda 表达式的主体:可以是一个表达式或一段代码块。如果是一个表达式,则不需要使用大括号 {} 包裹;如果是一段代码块,则需要使用大括号包裹,并且需要使用 return 关键字返回结果。

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

(parameters) -> expression
(parameters) -> { statements; }

示例 1:简单的 Lambda 表达式

假设我们有一个接口 MathOperation,其中定义了一个抽象方法 operate(int a, int b),用于执行某种数学操作。我们可以使用 Lambda 表达式来实现该接口的实例,如下所示:

interface MathOperation {
    int operate(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        // Lambda 表达式实现加法操作
        MathOperation addition = (a, b) -> a + b;
        System.out.println("5 + 3 = " + addition.operate(5, 3));
    }
}

示例 2:使用 Lambda 表达式遍历集合

另一个常见的用途是使用 Lambda 表达式遍历集合,如下所示:

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");
        
        // 使用 Lambda 表达式遍历集合
        names.forEach(name -> System.out.println(name));
    }
}

在这个示例中,我们使用 forEach 方法和 Lambda 表达式来遍历 names 集合,并打印出每个元素的值。

Lambda 表达式的优势

Lambda 表达式的引入使得代码变得更加简洁、易读,特别是在处理集合、事件监听器等场景下更为突出。通过 Lambda 表达式,可以减少冗余的代码,使得程序更加清晰和易于维护。因此,熟练掌握 Lambda 表达式是成为 Java 开发者的一项重要技能。

2. Stream API

Stream API 是 JDK 8 中另一个重要的新特性,它为集合操作提供了一种流式处理的方式。通过 Stream API,可以轻松地进行过滤、映射、排序等操作,而无需编写繁琐的循环结构。

Stream 的主要特性

  1. Stream 是不可变的:每次对 Stream 的操作都会返回一个新的 Stream。

  2. Stream 不存储数据:它们只处理从数据源(如集合、数组等)提供的数据。

  3. Stream 是惰性求值的:它们会延迟到真正需要结果的时候才执行。

Stream 的操作

Stream 操作分为中间操作和终端操作:

中间操作

中间操作返回一个新的 Stream,允许链式调用。这些操作是惰性求值的,仅在终端操作执行时才会实际处理数据。

  • filter(): 过滤元素

  • map(): 映射元素

  • flatMap(): 扁平化映射

  • distinct(): 去重

  • sorted(): 排序

  • peek(): 对每个元素执行操作并返回一个新的 Stream

终端操作

终端操作触发 Stream 的执行,并生成结果。终端操作之后,Stream 不能再被使用。

  • forEach(): 对每个元素执行操作

  • collect(): 收集结果到集合、数组等

  • count(): 计算元素数量

  • reduce(): 规约操作,将元素组合成一个值

  • toArray(): 将 Stream 转换为数组

  • findFirst(): 返回第一个元素

  • anyMatch(), allMatch(), noneMatch(): 匹配操作

Stream 的并行处理

Java 8 还引入了并行流,允许利用多核处理器来提高性能。可以使用 parallelStream()parallel() 方法将一个流转换为并行流。

并行处理会出现的问题

1. 线程安全问题

2. 不适合的小任务

3. 顺序依赖

4. 性能不一致

5. 合并操作的复杂性

6. 使用不适合的 Spliterator

7. 并行流的副作用

3. 接口的默认方法

JDK 8 引入了接口的默认方法,使得接口可以包含具有默认实现的方法。这为接口的演化提供了更大的灵活性,可以在不破坏现有实现的情况下向接口中添加新的方法。

4. 函数式接口和新的注解

JDK 8 提供了一些新的函数式接口,如 FunctionPredicateConsumer 等,使得在使用 Lambda 表达式时更加方便。此外,还引入了诸如 @FunctionalInterface@Repeatable 等新的注解,进一步增强了 Java 语言的表达能力。

@FunctionalInterface

这个注解用于标识一个接口为函数式接口。虽然没有这个注解也可以定义函数式接口,但使用它可以让编译器强制检查该接口是否满足函数式接口的要求(即只有一个抽象方法)。

@Repeatable

@Repeatable

这个注解用于定义可重复注解。在 Java 8 之前,同一个注解不能在同一声明或类型上重复使用。使用 @Repeatable 可以让注解在同一声明或类型上重复使用。

定义可重复注解

首先定义一个容器注解:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Schedules {
    Schedule[] value();
}

然后定义可重复注解,并使用 @Repeatable 指定容器注解:

import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Schedules.class)
public @interface Schedule {
    String day();
    String time();
}

然后定义可重复注解,并使用 @Repeatable 指定容器注解:

import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Schedules.class)
public @interface Schedule {
    String day();
    String time();
}

使用可重复注解

public class RepeatingAnnotations {

    @Schedule(day = "Monday", time = "9AM")
    @Schedule(day = "Tuesday", time = "10AM")
    public void scheduledTask() {
        // 方法实现
    }
}

通过反射可以访问这些重复注解:

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        try {
            Method method = RepeatingAnnotations.class.getMethod("scheduledTask");
            
            // 获取单个 Schedule 注解
            Schedule[] schedules = method.getAnnotationsByType(Schedule.class);
            for (Schedule schedule : schedules) {
                System.out.println(schedule.day() + " at " + schedule.time());
            }

            // 获取容器注解
            Schedules container = method.getAnnotation(Schedules.class);
            if (container != null) {
                for (Schedule schedule : container.value()) {
                    System.out.println(schedule.day() + " at " + schedule.time());
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

5. 新的日期和时间 API

JDK 8 引入了全新的日期和时间 API,以取代旧的 DateCalendar 类。新的 API 设计更加清晰、易用,并提供了丰富的操作方法,使得日期和时间的处理变得更加简单和安全。

6. Optional 类

  • Optional 是一个容器类,表示一个值可能存在也可能不存在。

  • 用于避免 NullPointerException。

  • 语法示例:Optional<String> optional = Optional.ofNullable(value);

文章作者: 知行合一
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 知行合一
喜欢就支持一下吧