第一天:Java 8核心特性复习

第一天:Java 8核心特性复习

Java 8是一个里程碑式的版本,于2014年3月发布,引入了许多革命性的特性,这些特性深刻地改变了Java编程范式。今天我们将全面复习Java 8的核心特性。

1. Lambda表达式

Lambda表达式是Java 8最重要的特性之一,它允许我们将行为(函数)作为参数传递,使代码更加简洁、可读性更强。

基本语法

// 无参数,无返回值
Runnable r1 = () -> System.out.println("Hello Lambda!");

// 有一个参数,无返回值(参数类型可以省略)
Consumer<String> c1 = (s) -> System.out.println(s);
Consumer<String> c2 = s -> System.out.println(s); // 单个参数可以省略括号

// 多个参数,有返回值
Comparator<Integer> cmp = (x, y) -> x - y;

// 代码块形式
BinaryOperator<Integer> add = (x, y) -> {
    System.out.println("Adding " + x + " and " + y);
    return x + y;
};
+----------------+       +----------------+
| 匿名内部类方式  |       | Lambda表达式方式 |
+----------------+       +----------------+
|                |       |                |
| new Runnable() |       | () ->          |
| {              |  -->  | System.out.    |
|   public void  |       | println("Hi"); |
|   run() {      |       |                |
|     System.out.|       |                |
|     println(   |       |                |
|     "Hi");     |       |                |
|   }            |       |                |
| }              |       |                |
+----------------+       +----------------+

函数式接口

Lambda表达式需要配合函数式接口使用。函数式接口是只有一个抽象方法的接口,可以使用@FunctionalInterface注解标记。

Java 8提供了许多内置的函数式接口:

// 常用函数式接口示例
Function<String, Integer> strLength = s -> s.length(); // 接收一个参数并返回一个结果
Predicate<Integer> isEven = n -> n % 2 == 0; // 接收一个参数并返回布尔值
Consumer<String> printer = s -> System.out.println(s); // 接收一个参数但不返回结果
Supplier<Double> random = () -> Math.random(); // 不接收参数但返回一个结果
BiFunction<Integer, Integer, Integer> sum = (a, b) -> a + b; // 接收两个参数并返回一个结果
+-------------------+----------------+------------------+
| 函数式接口         | 函数描述符      | 示例              |
+-------------------+----------------+------------------+
| Predicate<T>      | T -> boolean   | 检查苹果是否是红色  |
| Consumer<T>       | T -> void      | 打印一个数字       |
| Function<T,R>     | T -> R         | 获取苹果的重量     |
| Supplier<T>       | () -> T        | 创建一个苹果对象   |
| BiFunction<T,U,R> | (T,U) -> R     | 两个数字相加      |
| ...               | ...            | ...             |
+-------------------+----------------+------------------+

变量捕获

Lambda表达式可以捕获外部变量,但这些变量必须是effectively final的(即使不声明为final,也不能在Lambda中修改)。

int factor = 2;
Function<Integer, Integer> multiplier = n -> n * factor; // 捕获外部变量factor
// factor = 3; // 错误:Lambda表达式中使用的变量必须是effectively final的
+------------------+       +------------------+
| Lambda表达式外部  |       | Lambda表达式内部  |
+------------------+       +------------------+
| int factor = 2;  |  -->  | n -> n * factor  |
+------------------+       +------------------+
                           | factor不能被修改  |
                           +------------------+

2. 方法引用

方法引用是Lambda表达式的一种简化形式,当Lambda表达式的内容仅仅是调用一个已有的方法时,可以使用方法引用。

四种类型的方法引用

// 1. 静态方法引用:ClassName::staticMethodName
Function<String, Integer> parseInt = Integer::parseInt;

// 2. 实例方法引用:instance::methodName
String str = "Hello";
Supplier<Integer> length = str::length;

// 3. 对象方法引用:ClassName::methodName
Function<String, Integer> strLength = String::length;

// 4. 构造方法引用:ClassName::new
Supplier<List<String>> listSupplier = ArrayList::new;
+----------------------+-------------------------+---------------------------+
| 方法引用类型          | 语法                    | 对应的Lambda表达式         |
+----------------------+-------------------------+---------------------------+
| 静态方法引用          | ClassName::staticMethod | (args) -> ClassName.      |
|                      |                         | staticMethod(args)        |
+----------------------+-------------------------+---------------------------+
| 实例方法引用          | instance::method        | (args) -> instance.       |
|                      |                         | method(args)              |
+----------------------+-------------------------+---------------------------+
| 对象方法引用          | ClassName::method       | (instance, args) ->       |
|                      |                         | instance.method(args)     |
+----------------------+-------------------------+---------------------------+
| 构造方法引用          | ClassName::new          | (args) -> new ClassName   |
|                      |                         | (args)                    |
+----------------------+-------------------------+---------------------------+

3. Stream API

Stream API提供了一种函数式编程的方式来处理集合,使代码更加简洁、可读性更强。

创建Stream

// 从集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> streamFromList = list.stream();

// 从数组创建
String[] array = {"a", "b", "c"};
Stream<String> streamFromArray = Arrays.stream(array);

// 使用Stream.of
Stream<String> streamOf = Stream.of("a", "b", "c");

// 创建无限流
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1);
Stream<Double> randomStream = Stream.generate(Math::random);
+-------------+     +-------------+     +-------------+     +-------------+
| 数据源      |     | 中间操作    |     | 中间操作    |     | 终端操作    |
| (Collection)|     | (filter)    |     | (map)       |     | (collect)   |
+-------------+     +-------------+     +-------------+     +-------------+
       |                  |                  |                  |
       v                  v                  v                  v
   [1,2,3,4,5]  -->  [2,4]  -->  [4,16]  -->  [4,16]

中间操作

中间操作返回一个新的Stream,可以链式调用。

List<String> names = Arrays.asList("John", "Jane", "Jack", "Joe");

names.stream()
     .filter(name -> name.startsWith("J")) // 过滤
     .map(String::toUpperCase)            // 转换
     .sorted()                            // 排序
     .distinct()                          // 去重
     .limit(2)                            // 限制数量
     .forEach(System.out::println);       // 终端操作
+-------------+     +-------------+     +-------------+     +-------------+
| filter()    |     | map()       |     | sorted()    |     | limit()     |
+-------------+     +-------------+     +-------------+     +-------------+
| 筛选满足    |     | 将元素转换  |     | 对元素      |     | 截取前N个   |
| 条件的元素  |     | 为新元素    |     | 进行排序    |     | 元素        |
+-------------+     +-------------+     +-------------+     +-------------+

终端操作

终端操作会消费Stream并产生结果。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 收集结果
List<Integer> doubledList = numbers.stream()
                                  .map(n -> n * 2)
                                  .collect(Collectors.toList());

// 归约操作
int sum = numbers.stream().reduce(0, Integer::sum);

// 查找操作
Optional<Integer> first = numbers.stream().findFirst();

// 匹配操作
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0);
boolean noneEven = numbers.stream().noneMatch(n -> n % 2 == 0);

// 统计操作
long count = numbers.stream().count();
+-------------+     +-------------+     +-------------+
| 终端操作    |     | 返回类型    |     | 示例        |
+-------------+     +-------------+     +-------------+
| forEach     |     | void        |     | 遍历每个元素 |
| collect     |     | 集合        |     | 收集到List   |
| reduce      |     | Optional/T  |     | 求和、最大值 |
| count       |     | long        |     | 计算元素个数 |
| findFirst   |     | Optional<T> |     | 查找第一个   |
| anyMatch    |     | boolean     |     | 任一匹配     |
| allMatch    |     | boolean     |     | 全部匹配     |
| noneMatch   |     | boolean     |     | 全不匹配     |
+-------------+     +-------------+     +-------------+

Collectors类

Collectors类提供了许多有用的收集器,用于将Stream转换为集合或其他形式。

// 收集为List
List<String> list = stream.collect(Collectors.toList());

// 收集为Set
Set<String> set = stream.collect(Collectors.toSet());

// 收集为Map
Map<String, Integer> map = stream.collect(Collectors.toMap(s -> s, String::length));

// 连接字符串
String joined = stream.collect(Collectors.joining(", "));

// 分组
Map<Integer, List<String>> groupedByLength = stream.collect(Collectors.groupingBy(String::length));

// 分区
Map<Boolean, List<Integer>> partitioned = stream.collect(Collectors.partitioningBy(n -> n % 2 == 0));

// 统计
IntSummaryStatistics stats = stream.collect(Collectors.summarizingInt(String::length));
+------------------+     +------------------+
| Collectors方法   |     | 返回结果         |
+------------------+     +------------------+
| toList()         |     | ArrayList        |
| toSet()          |     | HashSet          |
| toMap(k,v)       |     | HashMap          |
| joining()        |     | String           |
| groupingBy()     |     | Map<K,List<T>>   |
| partitioningBy() |     | Map<Boolean,     |
|                  |     | List<T>>         |
| summarizingXxx() |     | XxxSummary       |
|                  |     | Statistics       |
+------------------+     +------------------+

并行流

Stream API支持并行处理,可以充分利用多核CPU的优势。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// 串行流
long startTime1 = System.currentTimeMillis();
numbers.stream().map(n -> performHeavyComputation(n)).collect(Collectors.toList());
long endTime1 = System.currentTimeMillis();
System.out.println("串行流耗时: " + (endTime1 - startTime1) + "ms");

// 并行流
long startTime2 = System.currentTimeMillis();
numbers.parallelStream().map(n -> performHeavyComputation(n)).collect(Collectors.toList());
long endTime2 = System.currentTimeMillis();
System.out.println("并行流耗时: " + (endTime2 - startTime2) + "ms");
串行流处理:
[1] -> [2] -> [3] -> [4] -> [5] -> [结果]

并行流处理:
     [1] -> [2] -+
                 |
     [3] -> [4] -+-> [合并] -> [结果]
                 |
     [5] -------+

4. Optional类

Optional类是一个容器对象,可以包含也可以不包含非空值,用于避免空指针异常。

// 创建Optional对象
Optional<String> optional1 = Optional.of("Hello"); // 不能为null
Optional<String> optional2 = Optional.ofNullable(null); // 可以为null
Optional<String> optional3 = Optional.empty(); // 空Optional

// 检查值是否存在
boolean isPresent = optional1.isPresent();
boolean isEmpty = optional1.isEmpty(); // Java 11+

// 获取值
String value1 = optional1.get(); // 如果为空会抛出NoSuchElementException
String value2 = optional2.orElse("Default"); // 如果为空返回默认值
String value3 = optional2.orElseGet(() -> "Computed Default"); // 如果为空通过Supplier获取默认值
String value4 = optional2.orElseThrow(() -> new RuntimeException("Value not present")); // 如果为空抛出异常

// 条件操作
optional1.ifPresent(s -> System.out.println(s)); // 如果存在值则执行Consumer
optional1.ifPresentOrElse(
    s -> System.out.println(s),
    () -> System.out.println("Empty") // Java 9+
);

// 转换操作
Optional<Integer> mapped = optional1.map(String::length);
Optional<Optional<Integer>> nested = optional1.map(s -> Optional.of(s.length()));
Optional<Integer> flatMapped = optional1.flatMap(s -> Optional.of(s.length()));

// 过滤操作
Optional<String> filtered = optional1.filter(s -> s.length() > 3);
+------------------+     +------------------+     +------------------+
| 传统null检查     |     | Optional方式     |     | 结果             |
+------------------+     +------------------+     +------------------+
| if(obj != null)  |     | optional         |     | 执行操作或       |
| {                |     | .ifPresent(      |     | 跳过             |
|   doSomething(); |     | this::doSomething|     |                  |
| }                |     | );               |     |                  |
+------------------+     +------------------+     +------------------+
| return obj != null|     | return optional  |     | 返回实际值或     |
| ? obj : default;  |     | .orElse(default);|     | 默认值           |
+------------------+     +------------------+     +------------------+
| if(obj == null)  |     | optional         |     | 值不存在时       |
| {                |     | .orElseThrow(    |     | 抛出异常         |
|   throw new Ex...|     | () -> new Ex...  |     |                  |
| }                |     | );               |     |                  |
+------------------+     +------------------+     +------------------+

5. 接口默认方法和静态方法

Java 8允许在接口中定义默认方法和静态方法,这些方法有默认实现,实现类可以选择覆盖或使用默认实现。

interface Vehicle {
    // 抽象方法
    void start();
    
    // 默认方法
    default void honk() {
        System.out.println("Beep beep!");
    }
    
    // 静态方法
    static Vehicle create() {
        return new Car();
    }
}

class Car implements Vehicle {
    @Override
    public void start() {
        System.out.println("Car started");
    }
    
    // 可以选择覆盖默认方法
    @Override
    public void honk() {
        System.out.println("Car honk: Beep beep!");
    }
}
+------------------+     +------------------+
| Java 8之前的接口 |     | Java 8的接口     |
+------------------+     +------------------+
| 只能包含:        |     | 可以包含:        |
| - 常量           |     | - 常量           |
| - 抽象方法       |     | - 抽象方法       |
|                  |     | - 默认方法       |
|                  |     | - 静态方法       |
+------------------+     +------------------+

多重继承问题

当一个类实现多个接口,而这些接口有相同的默认方法时,会出现多重继承问题。

interface A {
    default void foo() {
        System.out.println("A's foo");
    }
}

interface B {
    default void foo() {
        System.out.println("B's foo");
    }
}

// 编译错误:类C继承了接口A和B的相同方法foo()
class C implements A, B {
    // 必须覆盖foo方法解决冲突
    @Override
    public void foo() {
        // 可以选择调用其中一个接口的默认实现
        A.super.foo();
        // 或者
        // B.super.foo();
        // 或者提供自己的实现
    }
}
+------------------+     +------------------+
|    接口A         |     |    接口B         |
+------------------+     +------------------+
| default void foo()|     | default void foo()|
+------------------+     +------------------+
          ^                       ^
          |                       |
          +-----------------------+
                      |
                      v
              +------------------+
              |     类C          |
              +------------------+
              | @Override        |
              | void foo() {     |
              |   A.super.foo(); |
              | }                |
              +------------------+

6. 新的日期时间API

Java 8引入了新的日期时间API,位于java.time包下,解决了旧API的许多问题。

核心类

// 本地日期和时间
LocalDate date = LocalDate.now(); // 当前日期
LocalTime time = LocalTime.now(); // 当前时间
LocalDateTime dateTime = LocalDateTime.now(); // 当前日期和时间

// 创建特定的日期和时间
LocalDate specificDate = LocalDate.of(2023, 8, 17);
LocalTime specificTime = LocalTime.of(14, 30, 15);
LocalDateTime specificDateTime = LocalDateTime.of(2023, 8, 17, 14, 30, 15);

// 日期时间操作
LocalDate tomorrow = date.plusDays(1);
LocalDate lastMonth = date.minusMonths(1);
LocalDate firstDayOfMonth = date.withDayOfMonth(1);

// 时区
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime shanghaiTime = ZonedDateTime.now(zoneId);
ZonedDateTime newYorkTime = shanghaiTime.withZoneSameInstant(ZoneId.of("America/New_York"));

// 时间间隔
Period period = Period.between(LocalDate.of(2020, 1, 1), LocalDate.of(2023, 8, 17));
Duration duration = Duration.between(LocalTime.of(14, 0), LocalTime.of(15, 30));

// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = dateTime.format(formatter);
LocalDateTime parsedDateTime = LocalDateTime.parse("2023-08-17 14:30:15", formatter);
+------------------+     +------------------+     +------------------+
| 日期时间类型     |     | 时区处理         |     | 时间间隔         |
+------------------+     +------------------+     +------------------+
| LocalDate        |     | ZoneId           |     | Period           |
| LocalTime        |     | ZoneOffset       |     | Duration         |
| LocalDateTime    |     | ZonedDateTime    |     | ChronoUnit       |
| Instant          |     | OffsetDateTime   |     |                  |
+------------------+     +------------------+     +------------------+

时间戳和Instant

// 获取当前时间戳
Instant now = Instant.now();

// 从毫秒创建Instant
Instant instant = Instant.ofEpochMilli(System.currentTimeMillis());

// 在Instant上添加时间
Instant later = instant.plus(Duration.ofHours(2));

// 比较两个Instant
boolean isBefore = instant.isBefore(later);

// 转换为LocalDateTime
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

时钟

// 获取系统默认时钟
Clock clock = Clock.systemDefaultZone();

// 获取特定时区的时钟
Clock parisClock = Clock.system(ZoneId.of("Europe/Paris"));

// 固定时钟(用于测试)
Clock fixedClock = Clock.fixed(Instant.now(), ZoneId.systemDefault());

// 从时钟获取当前时间
Instant instant = clock.instant();
LocalDateTime dateTime = LocalDateTime.now(clock);
+------------------+     +------------------+
| 旧的日期时间API  |     | Java 8日期时间API|
+------------------+     +------------------+
| java.util.Date   |     | java.time.Local  |
| java.util.Calendar|     | Date/Time/      |
| java.text.Simple |     | DateTime         |
| DateFormat       |     |                  |
+------------------+     +------------------+
| 可变的           |     | 不可变的         |
| 非线程安全       |     | 线程安全         |
| 设计不一致       |     | 设计一致         |
| 处理困难         |     | API丰富易用      |
+------------------+     +------------------+

7. CompletableFuture

CompletableFuture提供了一种异步编程的方式,可以组合多个异步操作,处理异常,以及控制异步操作的执行。

创建和执行异步任务

// 创建CompletableFuture
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "Hello";
});

// 不返回结果的异步任务
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
    System.out.println("Running async task");
});

// 指定Executor
ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Hello", executor);

转换和组合

// 转换结果
CompletableFuture<Integer> future4 = future1.thenApply(s -> s.length());

// 消费结果
CompletableFuture<Void> future5 = future1.thenAccept(s -> System.out.println(s));

// 执行下一个操作(不使用上一个结果)
CompletableFuture<Void> future6 = future1.thenRun(() -> System.out.println("Done"));

// 组合两个CompletableFuture
CompletableFuture<String> future7 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> combinedFuture = future1.thenCombine(future7, (s1, s2) -> s1 + " " + s2);

// 组合多个CompletableFuture(所有完成后执行)
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future4, future7);

// 组合多个CompletableFuture(任意一个完成后执行)
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future4, future7);

7. CompletableFuture(续)

异常处理

// 处理异常
CompletableFuture<String> failedFuture = CompletableFuture.supplyAsync(() -> {
    if (true) throw new RuntimeException("Computation failed");
    return "Success";
});

CompletableFuture<String> recoveredFuture = failedFuture.exceptionally(ex -> "Recovered: " + ex.getMessage());

// 处理正常结果和异常
CompletableFuture<String> handledFuture = failedFuture.handle((result, ex) -> {
    if (ex != null) {
        return "Handled: " + ex.getMessage();
    } else {
        return result;
    }
});
+------------------+     +------------------+
| 传统异步编程     |     | CompletableFuture|
+------------------+     +------------------+
| 回调地狱         |     | 链式调用         |
| 异常处理困难     |     | 内置异常处理     |
| 组合操作复杂     |     | 丰富的组合API    |
| 手动线程管理     |     | 自动线程管理     |
+------------------+     +------------------+

等待完成

// 阻塞等待结果
String result = future1.get(); // 可能抛出异常
String resultWithTimeout = future1.get(1, TimeUnit.SECONDS); // 带超时的等待

// 非阻塞检查
boolean isDone = future1.isDone();
boolean isCancelled = future1.isCancelled();
boolean isCompletedExceptionally = future1.isCompletedExceptionally();

// 强制完成
future1.complete("Forced result");

// 强制异常完成
future1.completeExceptionally(new RuntimeException("Forced failure"));

// 取消任务
future1.cancel(true);

8. Base64编码

Java 8内置了Base64编码的支持。

// 基本编码
String text = "Hello, World!";
String encoded = Base64.getEncoder().encodeToString(text.getBytes());
byte[] decoded = Base64.getDecoder().decode(encoded);

// URL安全编码
String urlEncoded = Base64.getUrlEncoder().encodeToString(text.getBytes());
byte[] urlDecoded = Base64.getUrlDecoder().decode(urlEncoded);

// MIME编码
String mimeEncoded = Base64.getMimeEncoder().encodeToString(text.getBytes());
byte[] mimeDecoded = Base64.getMimeDecoder().decode(mimeEncoded);

// 带行长度限制的编码
int lineLength = 76;
String delimiter = System.lineSeparator();
Base64.Encoder encoder = Base64.getMimeEncoder(lineLength, delimiter.getBytes());
String encodedWithLineBreaks = new String(encoder.encode(text.getBytes()));
+------------------+     +------------------+
| Base64编码类型   |     | 用途             |
+------------------+     +------------------+
| 基本编码         |     | 标准Base64编码   |
| URL安全编码      |     | URL和文件名      |
| MIME编码         |     | 电子邮件等       |
+------------------+     +------------------+

9. 注解增强

Java 8增强了注解的功能,包括重复注解和类型注解。

重复注解

// 定义容器注解
@Retention(RetentionPolicy.RUNTIME)
@interface Schedules {
    Schedule[] value();
}

// 定义可重复注解
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Schedules.class)
@interface Schedule {
    String dayOfMonth() default "first";
    String dayOfWeek() default "Mon";
    int hour() default 12;
}

// 使用重复注解
@Schedule(dayOfMonth = "first", dayOfWeek = "Mon", hour = 12)
@Schedule(dayOfMonth = "last", dayOfWeek = "Fri", hour = 23)
public class RepeatingAnnotationsExample {
    // ...
}

// 获取重复注解
Schedule[] schedules = RepeatingAnnotationsExample.class.getAnnotationsByType(Schedule.class);
+------------------+     +------------------+
| Java 8之前       |     | Java 8重复注解   |
+------------------+     +------------------+
| @Schedules({     |     | @Schedule(...)   |
|   @Schedule(...),|     | @Schedule(...)   |
|   @Schedule(...) |     |                  |
| })               |     |                  |
+------------------+     +------------------+

类型注解

// 定义类型注解
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface NonNull {
}

// 使用类型注解
public class TypeAnnotationsExample {
    // 变量类型注解
    private @NonNull String text;
    
    // 泛型类型注解
    private List<@NonNull String> list;
    
    // 方法返回类型注解
    public @NonNull String getText() {
        return text;
    }
    
    // 方法参数类型注解
    public void setText(@NonNull String text) {
        this.text = text;
    }
    
    // 异常类型注解
    public void process() throws @NonNull Exception {
        // ...
    }
    
    // 类型转换注解
    String str = (@NonNull String) obj;
    
    // 数组类型注解
    @NonNull String[] array;
    
    // 接收者类型注解
    public void process(@NonNull TypeAnnotationsExample this) {
        // ...
    }
}
+------------------+     +------------------+
| 注解位置         |     | 示例             |
+------------------+     +------------------+
| 类型声明         |     | @NonNull String  |
| 泛型参数         |     | List<@NonNull T> |
| 方法返回类型     |     | @NonNull String  |
|                  |     | getText()        |
| 方法参数         |     | setText(@NonNull |
|                  |     | String text)     |
| 异常声明         |     | throws @NonNull  |
|                  |     | Exception        |
+------------------+     +------------------+

10. Nashorn JavaScript引擎

Java 8引入了新的JavaScript引擎Nashorn,替代了旧的Rhino引擎。

// 创建ScriptEngine
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");

// 执行JavaScript代码
engine.eval("print('Hello, Nashorn!')");

// 在JavaScript中调用Java方法
engine.eval("var System = Java.type('java.lang.System'); System.out.println('Hello from JavaScript!');");

// 在Java中调用JavaScript函数
engine.eval("function add(a, b) { return a + b; }");
Invocable invocable = (Invocable) engine;
Object result = invocable.invokeFunction("add", 1, 2);
System.out.println(result); // 输出: 3

// 在JavaScript中使用Java对象
engine.put("person", new Person("John", 30));
engine.eval("print(person.getName() + ' is ' + person.getAge() + ' years old')");

// 使用JavaScript对象
engine.eval("var jsObject = { name: 'John', age: 30 };");
Object jsObject = engine.get("jsObject");
+------------------+     +------------------+
| Rhino (旧)       |     | Nashorn (Java 8) |
+------------------+     +------------------+
| 性能较低         |     | 性能提升         |
| JSR-223支持      |     | JSR-223支持      |
| 不支持ECMAScript |     | 支持ECMAScript   |
| 5.1的所有功能    |     | 5.1及部分6功能   |
+------------------+     +------------------+

11. 并行数组操作

Java 8增强了Arrays类,添加了许多并行操作方法。

int[] numbers = {5, 3, 8, 1, 9, 2, 7, 4, 6};

// 并行排序
Arrays.parallelSort(numbers);

// 并行设置值
Arrays.parallelSetAll(numbers, i -> i * 2);

// 并行前缀操作
Arrays.parallelPrefix(numbers, (x, y) -> x + y);
+------------------+     +------------------+
| 串行数组操作     |     | 并行数组操作     |
+------------------+     +------------------+
| Arrays.sort()    |     | Arrays.parallel  |
|                  |     | Sort()           |
| 手动设置值       |     | Arrays.parallel  |
|                  |     | SetAll()         |
| 手动计算前缀和   |     | Arrays.parallel  |
|                  |     | Prefix()         |
+------------------+     +------------------+

12. StampedLock

Java 8引入了StampedLock,这是一种新的锁机制,支持乐观读取。

StampedLock lock = new StampedLock();

// 写锁
long stamp = lock.writeLock();
try {
    // 写入共享数据
} finally {
    lock.unlockWrite(stamp);
}

// 读锁
stamp = lock.readLock();
try {
    // 读取共享数据
} finally {
    lock.unlockRead(stamp);
}

// 乐观读
stamp = lock.tryOptimisticRead();
// 读取共享数据
if (!lock.validate(stamp)) {
    // 数据已被修改,获取读锁并重新读取
    stamp = lock.readLock();
    try {
        // 重新读取共享数据
    } finally {
        lock.unlockRead(stamp);
    }
}
+------------------+     +------------------+     +------------------+
| ReentrantLock    |     | ReadWriteLock    |     | StampedLock      |
+------------------+     +------------------+     +------------------+
| 互斥锁           |     | 读写锁           |     | 读写锁+乐观锁    |
| 可重入           |     | 读共享,写互斥   |     | 读共享,写互斥   |
| 不区分读写       |     | 区分读写         |     | 区分读写         |
| 不支持乐观读     |     | 不支持乐观读     |     | 支持乐观读       |
| 可条件等待       |     | 可条件等待       |     | 不可条件等待     |
+------------------+     +------------------+     +------------------+

13. 新的集合方法

Java 8为集合框架添加了一些新的方法。

// Map接口的新方法
Map<String, Integer> map = new HashMap<>();

// 如果键不存在则放入值
map.putIfAbsent("a", 1);

// 计算值
map.compute("a", (k, v) -> v == null ? 1 : v + 1);
map.computeIfAbsent("b", k -> k.length());
map.computeIfPresent("a", (k, v) -> v * 2);

// 合并值
map.merge("a", 1, (oldValue, newValue) -> oldValue + newValue);

// 遍历
map.forEach((k, v) -> System.out.println(k + ": " + v));

// 删除
map.remove("a", 1); // 只有当值为1时才删除

// List接口的新方法
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");

// 遍历
list.forEach(System.out::println);

// 排序
list.sort(Comparator.naturalOrder());
list.sort(Comparator.reverseOrder());
list.sort(Comparator.comparing(String::length));

// 替换所有元素
list.replaceAll(String::toUpperCase);

// 删除满足条件的元素
list.removeIf(s -> s.equals("a"));
+------------------+     +------------------+
| Map新方法        |     | List新方法       |
+------------------+     +------------------+
| putIfAbsent()    |     | forEach()        |
| compute()        |     | sort()           |
| computeIfAbsent()|     | replaceAll()     |
| computeIfPresent()|    | removeIf()       |
| merge()          |     |                  |
| forEach()        |     |                  |
+------------------+     +------------------+

14. 函数式编程增强

Java 8通过函数式接口和Lambda表达式,使Java支持函数式编程范式。

函数组合

// 函数组合
Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2;
Function<Integer, Integer> h = f.andThen(g); // g(f(x))
Function<Integer, Integer> i = f.compose(g); // f(g(x))

System.out.println(h.apply(1)); // (1 + 1) * 2 = 4
System.out.println(i.apply(1)); // (1 * 2) + 1 = 3

// 谓词组合
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();
Predicate<String> isShort = s -> s.length() < 5;
Predicate<String> isEmptyOrShort = isEmpty.or(isShort);
Predicate<String> isNotEmptyAndShort = isNotEmpty.and(isShort);
+------------------+     +------------------+
| 函数组合         |     | 谓词组合         |
+------------------+     +------------------+
| f.andThen(g)     |     | p.negate()       |
| f.compose(g)     |     | p.and(q)         |
| Function.identity()|   | p.or(q)          |
+------------------+     +------------------+

柯里化和部分应用

// 柯里化
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
Function<Integer, Function<Integer, Integer>> curriedAdd = a -> b -> a + b;

// 使用柯里化函数
Function<Integer, Integer> add5 = curriedAdd.apply(5);
System.out.println(add5.apply(3)); // 5 + 3 = 8

// 部分应用
BiFunction<Integer, Integer, Integer> multiply = (a, b) -> a * b;
Function<Integer, Integer> multiplyBy3 = b -> multiply.apply(3, b);
System.out.println(multiplyBy3.apply(4)); // 3 * 4 = 12
+------------------+     +------------------+
| 普通函数         |     | 柯里化函数       |
+------------------+     +------------------+
| add(a, b)        |     | add(a)(b)        |
| 一次接收所有参数 |     | 分步接收参数     |
+------------------+     +------------------+

15. 其他增强

StringJoiner

// 使用StringJoiner
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.add("a");
joiner.add("b");
joiner.add("c");
System.out.println(joiner.toString()); // [a, b, c]

// 使用String.join
String joined = String.join(", ", "a", "b", "c");
System.out.println(joined); // a, b, c

数值流

// IntStream
IntStream intStream = IntStream.range(1, 5); // 1, 2, 3, 4
IntStream intStream2 = IntStream.rangeClosed(1, 5); // 1, 2, 3, 4, 5

// LongStream
LongStream longStream = LongStream.range(1L, 5L);

// DoubleStream
DoubleStream doubleStream = DoubleStream.of(1.0, 2.0, 3.0);

// 数值流操作
int sum = IntStream.rangeClosed(1, 100).sum();
OptionalDouble avg = IntStream.rangeClosed(1, 100).average();
IntSummaryStatistics stats = IntStream.rangeClosed(1, 100).summaryStatistics();
+------------------+     +------------------+
| 普通Stream       |     | 数值Stream       |
+------------------+     +------------------+
| Stream<Integer>  |     | IntStream        |
| 需要装箱/拆箱    |     | 无装箱/拆箱      |
| 无特殊数值操作   |     | sum(), average() |
|                  |     | max(), min()     |
+------------------+     +------------------+

Files类增强

// 读取所有行
List<String> lines = Files.readAllLines(Paths.get("file.txt"));

// 使用Stream读取行
try (Stream<String> lineStream = Files.lines(Paths.get("file.txt"))) {
    lineStream.forEach(System.out::println);
}

// 遍历目录
try (Stream<Path> pathStream = Files.walk(Paths.get("."))) {
    pathStream.filter(Files::isRegularFile)
              .forEach(System.out::println);
}

// 查找文件
try (Stream<Path> pathStream = Files.find(Paths.get("."), 10,
        (path, attr) -> attr.isRegularFile() && path.toString().endsWith(".java"))) {
    pathStream.forEach(System.out::println);
}
+------------------+     +------------------+
| Files新方法      |     | 用途             |
+------------------+     +------------------+
| lines()          |     | 流式读取文件行   |
| walk()           |     | 遍历目录树       |
| find()           |     | 查找文件         |
| list()           |     | 列出目录内容     |
+------------------+     +------------------+

总结

Java 8引入了许多革命性的特性,这些特性深刻地改变了Java编程范式,使Java更加现代化、简洁和高效。这些特性包括:

  1. Lambda表达式和函数式接口
  2. 方法引用
  3. Stream API
  4. Optional类
  5. 接口默认方法和静态方法
  6. 新的日期时间API
  7. CompletableFuture
  8. Base64编码
  9. 注解增强
  10. Nashorn JavaScript引擎
  11. 并行数组操作
  12. StampedLock
  13. 新的集合方法
  14. 函数式编程增强
  15. 其他增强(StringJoiner、数值流、Files类增强等)

掌握这些特性对于提高开发效率和代码质量至关重要。在接下来的学习中,我们将基于Java 8,逐步学习Java 9到Java 25的新特性。

+------------------+
|   Java 8特性     |
+------------------+
|                  |
| Lambda表达式     |
| 方法引用         |
| Stream API       |
| Optional类       |
| 默认方法         |
| 新日期时间API    |
| CompletableFuture|
| Base64编码       |
| 注解增强         |
| Nashorn引擎      |
| 并行数组操作     |
| StampedLock      |
| 新集合方法       |
| 函数式编程增强   |
| 其他增强         |
|                  |
+------------------+

练习

  1. 使用Lambda表达式和Stream API对一个字符串列表进行过滤、转换和排序。
  2. 使用Optional类处理可能为null的对象。
  3. 使用CompletableFuture实现多个异步操作的组合。
  4. 使用新的日期时间API计算两个日期之间的天数。
  5. 定义一个带有默认方法的接口,并实现该接口。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值