Inside Java Newscast #1 解读(上)

简介: Inside Java Newscast #1 解读(上)

⎯⎯⎯⎯⎯⎯ Chapters ⎯⎯⎯⎯⎯⎯

  • 0:00 - Intro
  • 0:57 - Java 16 – Intro
  • 1:16 - Java 16 – Records
  • 1:43 - Java 16 – Type Pattern Matching
  • 1:58 - Java 16 – Sealed Classes - Preview
  • 2:25 - Java 16 – Stream API
  • 2:51 - Java 16 – HTTP/2 API
  • 3:14 - Java 16 – Unix Domain Sockets
  • 3:32 - Java 16 – Project Panama (Incubating)
  • 4:07 - Java 16 – JDK Flight Recorder
  • 4:39 - Java 16 – jpackage
  • 5:02 - Java 16 – Performance
  • 5:23 - Java 16 – Security
  • 5:48 - Java 16 – Ports
  • 5:55 - Java 16 – Deprecations/Limitations
  • 6:49 - Java 16 – Outro
  • 7:08 - Java 17
  • 7:22 - Java 17 – Another Port
  • 7:34 - Java 17 – Applet for Removal
  • 7:55 - Java 17 – Sealed Classes
  • 8:12 - Outro

Java 16 – Records

相关 JEP 地址:

Records 这个特性我仔细研究过实现:参考我写的另一篇文章Java Record 的一些思考 - 默认方法使用以及基于预编译生成相关字节码的底层实

简单说来其实就是(编译后查看下字节码就能看出来),在编译后,根据 Record 源码插入相关域与方法的字节码,包括:

  1. 自动生成的 private final field
  2. 自动生成的全属性构造器
  3. 自动生成的 public getter 方法
  4. 自动生成的 hashCode(),equals(),toString() 方法:
  5. 从字节码可以看出,这三个方法的底层实现是 invokeDynamic 另一个方法
  6. 调用的是 ObjectMethods.java 这个类中的 bootstrap 方法

这个还让我闹了个笑话,我以为这个是 Project Valhala 的 Inline Object 已经实现了(参考我的这个系列: JEP 尝鲜系列),还去 StackOverflow 问,这个 Record 为啥能有 wait() 方法,并且可以进行 synchronized 同步(因为如果是 Project Valhala 的 Inline Object 的话是没有普通类的对象头的,没法用普通类对象的方法实现同步),结果。。。。。最后还是 Goetz 大佬一眼就看出我是误会了


image.png


Record 这个特性当初是为了适应什么场景设计的,以及某些设计为何被舍弃,可以参考 Gotez 大佬的这篇文章 java-14-feature-spotlight. 其重中主要的看点总结如下:

1.Java Records 最常用于的地方就是方法多个返回结果,原来我们可能需要用 Apache-commons 里面的 Pair 或者 Tuple 这样的对象封装,或者自己新建一个类型。现在可以使用 Record。

2.第二个常见应用即在 Stream 中传递的过程中保持原有对象,并且减少运算,例如 Stream 排序:

List<Player> topN
        = players.stream()
             .sorted(Comparator.comparingInt(p -> getScore(p)))
             .limit(N)
             .collect(toList());

这么写的话,每次作比较都会调用一次 getScore(p),这个调用次数是 O(n^2)。利用 Record 可以用比较少的代码和改动实现减少运算:

record PlayerScore(Player player, Score score) {
    // convenience constructor for use by Stream::map
    PlayerScore(Player player) { this(player, getScore(player)); }
}
List<Player> topN
    = players.stream()
             .map(PlayerScore::new)
             .sorted(Comparator.comparingInt(PlayerScore::score))
             .limit(N)
             .map(PlayerScore::player)
             .collect(toList());

最后再推荐下我写的这篇关于 Record 的序列化的一些解析和思考:Java Record 的一些思考 - 序列化相关


Java 16 – Type Pattern Matching


相关 JEP 地址:

类型模式匹配一直是一个呼声很高的特性,如果和下一小节的 Sealed Class 特性 以及 Patterns in switch 结合起来使用会有更好的效果,这个我们在下一节会更详细的说明.


Nicolai 对 Type Pattern Matching 的说明


Nicolai 的这篇文章 对 Type Pattern Matching 的说明非常详细,总结如下

原来需要这么写的代码:

void feed(Animal animal) {
    if (animal instanceof Elephant) {
      ((Elephant) animal).eatPlants();
    }
    else if (animal instanceof Tiger) {
      ((Tiger) animal).eatMeat();
  }
}


现在可以直接这么写


void feed(Animal animal) {
  if (animal instanceof Elephant elephant)
    elephant.eatPlants();
  else if (animal instanceof Tiger tiger)
    tiger.eatMeat();
}

不需要空指针判断,因为 instanceof 已经自带 null 判断了,符合条件的 Type Pattern Matching 变量不会为 null。并且, Type Pattern Matching 不支持向上匹配,因为这个没有意义,即下面的代码会编译报错:

public void upcast(String string) {
  // compile error
  if (string instanceof CharSequence sequence)
    System.out.println("Duh");
}

还有一个常用的地方即实现 equals:

// old
@Override
public boolean equals(Object o) {
  if (this == o)
    return true;
  if (!(o instanceof Equals))
    return false;
  Type other = (Type) o;
  return someField.equals(other.someField)
    && anotherField.equals(other.anotherField);
}
// new
@Override
public final boolean equals(Object o) {
  return o instanceof Type other
    && someField.equals(other.someField)
    && anotherField.equals(other.anotherField);
}


其实 Type Pattern Matching 是个语法糖


其实这个特性是一个语法糖,我们可以简单测试下:

public class TypePatternMatching {
  public static void main(String[] args) {
    Object object = new Object();
    if (object instanceof String s) {
      System.out.println("a");
    }
  }
}

查看编译后的字节码:

public class test.TypePatternMatching {
  public test.TypePatternMatching();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/Object
       3: dup
       4: invokespecial #1                  // Method java/lang/Object."<init>":()V
       7: astore_1
       8: aload_1
       9: instanceof    #7                  // class java/lang/String
      12: ifeq          28
      15: aload_1
      16: checkcast     #7                  // class java/lang/String
      19: astore_2
      20: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      23: ldc           #15                 // String a
      25: invokevirtual #17                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      28: return
}

可以看出,字节码其实和下面的写法是一样的:

public static void main(String[] args) {
    Object object = new Object();
    if (object instanceof String) {
        String s = (String)object;
        System.out.println("a");
    }
}

大家可以反编译下这个 class,就能看出来。


Java 16 – Sealed Classes - Preview


Sealed Class 在 Java 17 已经发布了,相关的 JEP 如下:

在某些情况下,我们可能想枚举一个接口的所有实现类,例如:

interface Shape { }
record Circle(double radius) implements Shape { }
record Rectangle(double width, double height) implements Shape { }
double area(Shape shape) {
  if (shape instanceof Circle circle)
    return circle.radius() * circle.radius() * Math.PI;
  if (shape instanceof Rectangle rect)
    return rect.width() * rect.height();
  throw new IllegalArgumentException("Unknown shape");
}

我们如何能确定我们枚举完了所有的 Shape 呢? Sealed Class 这个特性为我们解决这个问题,Sealed Class 可以在声明的时候就决定这个类可以被哪些类继承:

sealed interface Shape permits Rectangle, Circle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
double area(Shape shape) {
  if (shape instanceof Circle circle)
    return circle.radius() * circle.radius() * Math.PI;
  if (shape instanceof Rectangle rect)
    return rect.width() * rect.height();
  throw new IllegalArgumentException("Unknown shape");
}

Sealed Class (可以是 abstract class 或者 interface )在声明时需要指定所有的实现类的名称。针对继承类,有如下限制:

  • Sealed Class 的继承类必须和 Sealed Class 在同一个模块下,如果没有指定模块,就必须在同一个包下
  • 每个继承类必须直接继承 Sealed Class,不能间接继承
  • 每个继承类必须是下面三种之一:
  • final 的 class,Java Record 本身就是 final 的
  • sealed 的 class,可以进一步指定会被哪些子类实现
  • non-sealed 的 class,也是一种扩展,但是打破 Sealed Class 的限制,Sealed Class 不知道也不关心这种的继承类还会有哪些子类。


相关文章
|
安全 算法 Java
Inside Java Newscast #1 解读(下)
Inside Java Newscast #1 解读(下)
Inside Java Newscast #1 解读(下)
|
网络协议 算法 Java
Inside Java Newscast #1 解读(中)
Inside Java Newscast #1 解读(中)
Inside Java Newscast #1 解读(中)
|
4天前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
42 17
|
15天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
17天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
17天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
17天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
42 3
|
17天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
101 2
|
25天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
48 6
|
2月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####