JDK9-17

create by nohi 20230117

简要记录JDK变化

JDK9

模块化在新窗口打开

1 模块化

  • 目标

    (1)可靠的配置

    (2)强封装

    (3)模块化JDK/JRE

  • 内容

    • requires其他模块(或依赖于)的列表

      requires语句用于指定一个模块对另一个模块的依赖,requires语法如下:
      requires [transitive] [static] <module>;
      <module>:是当前模块读取的另一个模块的名称;
      static:则<module>模块在编译时是必需的,但在运行时是可选的;
      transitive:级联依赖;
      
    • exports包列表(其public API),其他模块可以使用

    • open的包(整个API,共有和私有),其他模块可以反射调用

    • 使用的服务列表

    • 提供的服务的实现列表

  • 聚合模块

    可以创建一个不包含任何代码的模块,它收集并重新导出其他模块的内容,这样的模块称为聚合模块。假设有一个模块依赖于五个模块,可以为这五个模块创建一个聚合模块,现在你的模块只要依赖于一个模块--聚合模块。

  • 声明模块

    [open] module <moduleName> {
      <module-statement>;
      ......
    }
    

    open修饰符是可选的,它声明一个开放的模块,一个开放的模块导出所有的包,以便其他模块使用反射访问。<moduleName>是要定义的模块的名称,<module-statement>是一个模块语句。模块声明中可以包含零个或多个模块语句:

    • 导出语句(exports),导出模块,其他模块访问。

      exports <package> to <module1>, <module2>;

    • 开放语句(opens),开放当前模块,其他模块可以访问,包括反射调用等。

      opens <package>;
      opens <package> to <module1>, <module2>……
      <package>仅用于深层反射到<module1>,<module2>等。
      
    • 需要语句(requires),声明模块对另一个模块的依赖关系。

      requires <module>;
      requires transitive <module>;
      requires static <module>;
      requires transitive static <module>;
      
      static标示在编译时的依赖是强制的,但在运行时是可选的:requires static N意味着模块M需要模块N,模块N必须在编译时出现才能编译模块M,而在运行时存在模块N是可选的。
      transitive当前模块依赖其他模块具有隐式依赖性,假设有三个模块P,Q和R,假设模块Q包含requires transitive R语句,如果模块P包含requires Q,这意味着模块P隐含依赖模块R。
      
    • 使用语句(uses),表达服务消费。

      use语句可以指定服务接口的名字,当前模块就会发现它,使用java.util.ServiceLoader类进行加载:

      uses <service-interface>

    • 提供语句(provides),表达服务提供。

  • 模拟约束

    (1)将包拆分成多个模块是不允许的,也就是说,同一个包不能在多个模块中定义;

    (2)不能同时访问多个模块中的相同软件包;

    (3)模块图不能包含循环依赖,也就是说两个模块不能彼此读取,如果需要,他们应该是一个模块,而不是两个;

    (4)模块声明不支持模块版本,需要使用jar工具或其他一些工具(javac)将模块的版本添加为类文件属性;

    (4)模块系统没有子模块的概念,com.jdk9.address和com.jdk9.address.child是两个单独的模块。

目测模块化,exports目录不能包含下级目录。

module jdk9.module1 {
    exports nohi.jdk9.module1.user;
    exports nohi.jdk9.module1.user.addres;
}

2 jshell

命令行窗口,快速的运行一些简单的代码

╰─➤  jshell        # 调用jshell命令窗口
|  欢迎使用 JShell -- 版本 18.0.2
|  要大致了解该版本, 请键入: /help intro

jshell> System.out.println("HelloWorld");
HelloWorld

jshell> /exit       # 退出
|  再见

3 接口私有方法

public interface MyInterface {
    //定义私有方法
    private void m1() {
        System.out.println("123");
    }

    //default中调用
    default void m2() {
        m1();
    }
}

4 改进的try with resource

public class TryWithResouce {
    public void testTryWithResource(String src, String target) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream(src);
        FileOutputStream fos = new FileOutputStream(target);
        try (fis; fos) {
            byte[] is = new byte[1024];
            int length;
            while ((length = fis.read(is)) > -1) {
                fos.write(is, 0, length);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
// 测试类
@org.junit.jupiter.api.Test
void testTryWithResource() throws FileNotFoundException {
	TryWithResouce tr = new TryWithResouce();
	String src = "./pom.xml";
	String target =  "./pom_target.xml";
	tr.testTryWithResource(src, target);
}

5 不能使用下划线命名变量

6 String字符串的变化,String内部的char数组改成了byte数组

JDK10

1.局部变量类型推断

var str = "ABC"; //根据推断为 字符串类型
var l = 10L;//根据10L 推断long 类型
var flag = true;//根据 true推断 boolean 类型
var flag1 = 1;//这里会推断boolean类型。0表示false 非0表示true
var list = new ArrayList<String>();  // 推断 ArrayList<String>
var stream = list.stream();          // 推断 Stream<String>

其他

  • 将JDK多存储库合并为单存储库
  • 垃圾回收接口
  • 并行Full GC 的G1
  • 应用数据共享
  • 线程局部管控
  • 移除Native-Header Generation Tool (javah)
  • Unicode 标签扩展
  • 备用内存设备上分配堆内存
  • 基于实验JAVA 的JIT 编译器
  • Root 证书
  • 基于时间的版本控制

JDK11

2018年9 月 26 日

ZGC、Http Client

参考:https://www.jianshu.com/p/84a6050c5391

1 直接运行

java Hello.java

2 String新增方法

// unicode 空白符
 char c = '\u2000';
 String str = c + "abc" + c;
 System.out.println(String.format("[%s]", str));
 System.out.println(String.format("trim[%s]", str.trim()));
 System.out.println(String.format("strip[%s]", str.strip()));
 str = " abc ";
 System.out.println(String.format("[%s]", str));
 System.out.println(String.format("trim[%s]", str.trim()));
 System.out.println(String.format("strip[%s]", str.strip()));
  • 输出

    [ abc ]
    trim[ abc ]
    strip[abc]
    [ abc ]
    trim[abc]  str.trim()可以删除空格
    strip[abc]
    
// 判断字符串是否为空白
" ".isBlank(); // true
// 去除首尾空格
" Javastack ".strip(); // "Javastack"
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
// 复制字符串
"Java".repeat(3);// "JavaJavaJava"
// 行数统计
"A\nB\nC".lines().count(); // 3

3 局部变量类型推断

Lambda表达式中,可以使用var关键字来标识变量,变量类型由编译器自行推断

public static void main(String[] args) {
  Arrays.asList("Java", "Python", "Ruby")
        .forEach((var s) -> {
           System.out.println("Hello, " + s);
        });
}

4 Stream

// 0
Stream.ofNullable(null).count();
// [1, 2]
Stream.of(1, 2, 3, 2, 1).takeWhile(n -> n < 3).collect(Collectors.toList());
// [3, 2, 1]
Stream.of(1, 2, 3, 2, 1).dropWhile(n -> n < 3).collect(Collectors.toList());

5 Optional

// javastack
var msg = Optional.of("javastack").orElseThrow();
System.out.println("msg:" + msg);
System.out.println("msg.orElse:" + Optional.ofNullable(null).orElse("11111"));
// 1
long count = Optional.of("javastack").stream().count();
System.out.println("count:" + count);
// javastack
var obj = Optional.ofNullable(null).or(() -> Optional.of("javastack")).get();
System.out.println("obj:" + obj);

// 没有值,抛出异常
System.out.println("msg.orElse:" + Optional.ofNullable(null).orElseThrow());

6 InputStream

transferTo inputStrem -> OutputStream

var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("application.yml");
var javastack = File.createTempFile("application-target", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
	inputStream.transferTo(outputStream);
}
System.out.println("java.io.tmpdir:" + System.getProperty("java.io.tmpdir"));

7 HTTP Client API

var request = HttpRequest.newBuilder().uri(URI.create("https://www.baidu.com")).GET().build();
var client = HttpClient.newHttpClient();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 异步
client.sendAsync(request,HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body).thenAccept(System.out::println);

8 读写文件

对Files类增加了writeStringreadString两个静态方法,可以直接把String写入文件,或者把整个文件读出为一个String:

  System.out.println(Path.of("./").toAbsolutePath());;
  Files.writeString(
  	// 路径
  	Path.of("./", "tmp.txt"),
  	// 内容
  	"hello, jdk11 files api",
  	// 编码
  	StandardCharsets.UTF_8);
  String s = Files.readString(
  	// 路径
  	Paths.get("./tmp.txt"),
  	// 编码
  	StandardCharsets.UTF_8);
  System.out.println(s);

JDK12

1 switch

无break

 		static final int MONDAY = 1;
    static final int TUESDAY = 2;
    static final int WEDNESDAY = 3;
    static final int THURSDAY = 4;
    static final int FRIDAY = 5;
    static final int SATURDAY = 6;
    static final int SUNDAY = 7;

    public void doSwitch(int day) {
        switch (day) {
            case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
            case TUESDAY -> System.out.println(7);
            case THURSDAY, SATURDAY -> System.out.println(8);
            case WEDNESDAY -> System.out.println(9);
            default -> System.out.println("default");
        }
    }

2 Shenandoah GC

Redhat 主导开发的 Pauseless GC 实现,从大概 2013 年开始研发,终于取得了重要的阶段性成果,与其他 Pauseless GC 类似,Shenandoah GC 主要目标是 99.9% 的暂停小于 10ms,暂停与堆大小无关等。

3 支持Unicode 11.0

JDK 12版本包含对Unicode 11.0.0的支持。 在支持Unicode 10.0.0的JDK 11发行之后,Unicode 11.0.0引入了JDK 12现在包含的以下新功能:

  • 684个新字符
  • 11个新blocks
  • 7个新脚本。

4 NumberFormat增加了对以紧凑格式格式化数字的支持

 NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
 String result = fmt.format(1000);
 System.out.println("result1:" + result);
 result = fmt.format(1000000);
 System.out.println("result2:" + result);
# 结果
result1:1K
result2:1M

JDK13

1 switch表达式

传统的case ...:labels(需要break)或新case ...->labels(不需要break) ,还有另一个新语句,用于从switch表达式产生值

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;
};

2 文本块

 String text = """
                第一行
                第二行
                第三行
                """;
System.out.println(text);

java.lang.Character支持12.1级别的Unicode字符数据库,其中12.0自11.0起增加了554个字符,总共137,928个字符。

3 ZGC的增强

4 支持Unicode 12.1

JDK14

1 instanceof匹配

Object obj = 1;
// 自动传值至变量abc
if (obj instanceof Integer abc) {
	System.out.println(abc);
}

2 空指针提示

3 record类型

record Student(String name, int age) {
	public void daydayUp() {
  	System.out.println(String.format("[%s][%s] daydayup", name, age));
  }
}

@Test
public void testRecord() {
	Student student = new Student("NOHI", 18);
	System.out.println(student);
	student.daydayUp();
}

JDK15

2020/09/15 发布

1 密封类Sealed Classes (预览特性)

2 文本块功能转正

3 Shenandoah 垃圾回收算法转正

JDK 16

2021/03/16发布

1 instanceof 功能转正

if (object instanceof Kid kid) {
// ...
} else if (object instanceof Kiddle kiddle) {
// ...
}

2 Records 转正

3 ZGC

ZGC 最早是在 JDK 11 中集成进来的,在 JDK 15 中正式转正。

这个版本则是为了让 ZGC 支持并发栈处理,解决了最后一个重大瓶颈,把 ZGC 中的线程栈处理从安全点移到了并发阶段。并且还提供了一种机制,使得其他 HotSpot 子系统可以通过该机制延迟处理线程栈。

JDK17

1 switch

public void animalMoving(Animal animal) {
        switch (animal){
            case Rabbit r -> r.run();
            case Bird b -> b.fly();
            case null -> System.out.println("null....");
            default -> animal.moving();
        }
}

2 密封类转正

JDK18

1 默认使用UTF-8字符编码

-Dfile.encode=UTF-8

2 简单web服务器

jwebserver

3 将被移除的方法

Object中的finalize方法,Thread中的stop方法将在未来被删除

上次更新:
贡献者: NOHI