一 前述

1)jshell 2)局部变量的类型推断 3)新增的API

1.1 Java11是一个长期支持的版本(LTS)

1)对于企业来说,选择Java11将意味着长期的,可靠的,可预测的技术路线。其中免费的 openJDK11 确定将得到openJDK社区的长期支持,LTS是可以放心选择的版本。
2)从JVM GC的角度来看,JDK11 引入了两种新的GC,其中包括了也许是划时代的意义的ZGC,虽然其目前还是实验特性,但是从能力上看,这是JDK的一个巨大的突破,为特定生产环境的苛刻需求提供了一个可能的选择。

二 JShell

2.1 JShell概述

1)JShell类似于Python的shell工具
2)JShell是个交互性工具,可以让Java像脚本语言一样运行,可以从控制台上启动jshell,在jshell中直接输入表达式并查看结果
3)适用于测试一个方法或者是对表达式求值时

  1. C:\Program Files\Java\jdk11.0.8_10\bin>jshell
  2. | 欢迎使用 JShell -- 版本 11.0.8
  3. | 要大致了解该版本, 请键入: /help intro
  4. jshell> System.out.print("halo java")
  5. halo java
  6. jshell>

2.2 创建类和方法

1)Jshell类似于Java的main方法,但是也可以创建类和方法
2)不需要再解析main方法,直接执行语句时,就相当于在main方法中运行了

三 局部变量类型判断

3.1 创建maven项目

  1. <build>
  2. <plugins>
  3. <!-- 设置maven项目的jdk编译版本 -->
  4. <plugin>
  5. <groupId>org.apache.maven.plugins</groupId>
  6. <artifactId>maven-compiler-plugin</artifactId>
  7. <version>3.8.1</version>
  8. <configuration>
  9. <source>1.11</source>
  10. <target>1.11</target>
  11. </configuration>
  12. </plugin>
  13. </plugins>
  14. </build>

3.2 var 局部变量类型推断

1)var a = 10; 这个表达式可以由10推断出a的类型为int 2)但是 var a; 这样不赋值的表达式不可以,因为无法推断出a的类型是什么 3)在类声明属性的时候,不可以使用var 4)var不是一个关键字,int var = 10; 这样是可以运行的,var为变量名

  1. @Test
  2. public void test1(){
  3. int var =10;
  4. System.out.println(var);
  5. }

1)在lambda表达式中使用

  1. @Test
  2. public void test2() {
  3. Consumer consumer = (@Deprecated var x) -> { // var 可以推断出 x 的类型
  4. System.out.println(x);
  5. };
  6. consumer.accept(10);
  7. }

2)在lambda表达式上使用var还是和原来一样,有什么作用呢?

  • 一般使用lambda表达式,如果不知道类型,那么就无法在参数上使用注解,加上了var之后,可以使用注解来修饰参数

四 集合新增的API

4.1 List.of()

  1. @Test
  2. public void test1() {
  3. List<Integer> list = List.of(1, 2, 3, 4, 5);
  4. // list.add(6); 不允许新增元素,会报异常 java.lang.UnsupportedOperationException
  5. System.out.println(list);
  6. }

1)Arrays.asList()方法也可以创建集合对象

  1. @Test
  2. public void test2() {
  3. String[] arr = {"a", "bb", "cccc"};
  4. List<String> strings = Arrays.asList(arr);
  5. //strings.add("dd"); 也不允许添加元素
  6. System.out.println(strings);
  7. }

2)上面两者返回的集合对象不同,Arrays返回的是自己内部类的ArrayList类对象,List.of() 方法返回的是 ImmutableCollections.ListN<> 类对象,这是List接口中的一个static final内部类,不允许添加新的元素。

4.1 Set.of()

1)和List一样,返回一个Set对象
2)of方法中有相同元素时,会提示异常

  1. @Test
  2. public void test3() {
  3. Set<Integer> set = Set.of(1, 2, 3, 41, 1);
  4. System.out.println(set);
  5. // java.lang.IllegalArgumentException: duplicate element: 1
  6. }

3)当添加新元素时,不允许

  1. @Test
  2. public void test3() {
  3. Set<Integer> set = Set.of(1, 2, 3, 41);
  4. // set.add(55); java.lang.UnsupportedOperationException
  5. System.out.println(set);
  6. }

五 Stream新增的API

流的基本操作步骤
1)创建流
2)中间操作
3)终止操作
Stream是Java8的新特性,Java9开始对Stream增加了4个新方法

5.1 增加单个参数构造器,可以null

1)Stream.of(null) 会提示空指针异常

  1. @Test
  2. public void test2(){
  3. Stream<Object> stream = Stream.of(null);
  4. /**
  5. * 1 先调用这个方法,参数为数组对象
  6. * public static<T> Stream<T> of(T... values) {
  7. * return Arrays.stream(values);
  8. * }
  9. * 2 Stream()构造器的第三个参数为数组长度,null.length则直接提示空指针异常
  10. * ---> public static <T> Stream<T> stream(T[] array) {
  11. * return stream(array, 0, array.length);
  12. * }
  13. */
  14. }

2)Stream.ofNullable(null):完美解决这个问题

5.2 takeWhile()、dropWhile()

1)takeWhile:从流中一直获取判定器为真的元素,一旦遇到元素为假,就终止处理,丢弃后面的元素

  1. // JDK11源码
  2. default Stream<T> takeWhile(Predicate<? super T> predicate) {
  3. Objects.requireNonNull(predicate);
  4. // Reuses the unordered spliterator, which, when encounter is present,
  5. // is safe to use as long as it configured not to split
  6. return StreamSupport.stream(
  7. new WhileOps.UnorderedWhileSpliterator.OfRef.Taking<>(spliterator(), true, predicate),
  8. isParallel()).onClose(this::close);
  9. }
  1. // 示例代码
  2. @Test
  3. public void test3() {
  4. Stream<Integer> stream = Stream.of(5, 2, 4, 5, 5, 1);
  5. Stream<Integer> stream1 = stream.takeWhile((x) -> {
  6. if (x > 2) {
  7. return true;
  8. } else {
  9. return false;
  10. }
  11. });
  12. stream1.forEach(System.out::println); // 5
  13. }

2)dropWhile:从流中开始丢弃判定器为真的元素,一旦遇到假的,则返回后面的所有元素

  1. // JDK11源码
  2. default Stream<T> dropWhile(Predicate<? super T> predicate) {
  3. Objects.requireNonNull(predicate);
  4. // Reuses the unordered spliterator, which, when encounter is present,
  5. // is safe to use as long as it configured not to split
  6. return StreamSupport.stream(
  7. new WhileOps.UnorderedWhileSpliterator.OfRef.Dropping<>(spliterator(), true, predicate),
  8. isParallel()).onClose(this::close);
  9. }
  1. // 示例代码
  2. @Test
  3. public void test() {
  4. Stream<Integer> stream = Stream.of(5, 2, 4, 5, 5, 1);
  5. stream.dropWhile(x -> {
  6. if (x > 2) {
  7. return true;
  8. }
  9. return false;
  10. }).forEach(System.out::println); // 2,4,5,5,1
  11. }

5.3 iterate重载

流的迭代,用于产生流,创建流

  1. @Test
  2. public void test4() {
  3. // 第一个参数是种子,第二个参数是单位运算符,对前一个元素进行操作生产下一个元素
  4. Stream<Integer> iterate = Stream.iterate(1, t -> t * 2 + 1);
  5. iterate.limit(10).forEach(System.out::println);
  6. System.out.println("============================");
  7. // 第二个参数是判定器,限制流的无限扩展
  8. // 这个iterate重载的方法是jak11新增
  9. Stream<Integer> stream = Stream.iterate(1, t -> t < 1000, t -> t * 2 + 1);
  10. stream.forEach(System.out::println);
  11. }

六 字符串和Optional

字符串新增的API主要是对空白字符的处理 1)isBlank() 2)strip() 3)stripLeading() 4)stripTrailing() 5)repeat() 6)lines()

6.1 String类新增的API

1)isBlank():判断是否为空白字符

  1. @Test
  2. public void test1() {
  3. // 1、str中包含了英文,中文的空格
  4. String str = " \n \r \t \n";
  5. boolean blank = str.isBlank();
  6. System.out.println(blank); // true
  7. }

2)strip():去除字符串的首尾的空白字符,包括英文和其他所有语言的空白字符
2.1)trim():同样去除字符串的首尾的空白字符,但是只去除码字小于等于32的空白字符,不能去除中文的空格,只能去除空格,tab键,和换行符。

  1. @Test
  2. public void test(){
  3. String str = " \n \r \t abc \n";
  4. String str1 = str.strip();
  5. System.out.println(str1); // abc
  6. System.out.println(str1.length()); // 3
  7. }

3)stripLeading():去除字符串头部的空白字符

  1. @Test
  2. public void test2(){
  3. String str = " \n \r \t abc \n ";
  4. String str1 = str.stripLeading();
  5. System.out.println(str1); // abc
  6. System.out.println(str1.length()); // 7
  7. }

4)stripTrailing():去除字符串尾部的空白字符

  1. @Test
  2. public void test3(){
  3. String str = " \n \r \t abc \n ";
  4. String str1 = str.stripTrailing();
  5. System.out.println(str1); // abc
  6. System.out.println(str1.length()); // 12
  7. }

5)repeat(n):复制字符串,参数表示复制次数

  1. @Test
  2. public void test4() {
  3. String str = "Java";
  4. String repeat = str.repeat(3);
  5. System.out.println(repeat); // JavaJavaJava
  6. }

6)lines():将字符串按照分隔符进行分割,然后返回一个流Stream

  1. @Test
  2. public void test5() {
  3. String str = "Java\nhalo";
  4. Stream<String> lines = str.lines(); // 实际上以换行符进行分割,返回一个流
  5. System.out.println("字符串行数:" + lines.count()); // 2
  6. }

6.2 Optional类新增的API

1)ofNullable()

  1. @Test
  2. public void test1(){
  3. // of(null):会抛出异常,不安全
  4. // Optional<Object> optional = Optional.of(null);
  5. // ofNullable():可以兼容空指针,但是实际传入null,也要注意小心
  6. Optional<Object> optional1 = Optional.ofNullable(null);
  7. Object op = optional1.orElse("null"); // 如果为空则返回参数的值
  8. System.out.println(op);
  9. }

七 HttpClient

Java9开始引入的一个处理 HTTP 请求的 HTTP Client API,该API 支持同步异步 在Java11中成为正式可以状态,可以在 java.net 包下找到这个API

7.1 同步请求

  1. @Test
  2. public void test() throws Exception {
  3. HttpClient httpClient = HttpClient.newHttpClient();
  4. HttpRequest request = HttpRequest.newBuilder(URI.create("https://www.baidu.com/")).build();
  5. HttpResponse.BodyHandler<String> bodyHandler = HttpResponse.BodyHandlers.ofString();
  6. // send():同步方法
  7. HttpResponse<String> response = httpClient.send(request, bodyHandler);
  8. System.out.println(response.body());
  9. }

7.2 异步请求

  1. @Test
  2. public void test1() throws ExecutionException, InterruptedException {
  3. HttpClient httpClient = HttpClient.newHttpClient();
  4. HttpRequest request = HttpRequest.newBuilder(URI.create("https://www.baidu.com/")).build();
  5. HttpResponse.BodyHandler<String> bodyHandler = HttpResponse.BodyHandlers.ofString();
  6. // sendAsync():异步方法
  7. CompletableFuture<HttpResponse<String>> sendAsync = httpClient.sendAsync(request, bodyHandler);
  8. HttpResponse<String> response = sendAsync.get();
  9. String body = response.body();
  10. System.out.println(body);
  11. }

EpsilonGC和ZGC

8.1 新的Epsilon垃圾收集器

1)jdk对这个新特性的描述:开发一个处理新的内存分配,但是不实现任何实际垃圾内存回收机制的GC,一旦可用堆内存用完,JVM就会退出
2)如果有 System.gc() 调用,实际上也什么都不会发生,这个场景下和 -XX:+DisableExplicitGC 效果一样,因为没有内存回收,这个实现可能会警告用户强制GC是徒劳的
3)使用EpsilonGC 的原因:

  • 提供完全被动的GC 实现,具有有限的分配限制,和尽可能低的延迟开销,但是代价是内存占用和内存吞吐量
  • 众所周知,Java实现可广泛选择高度可配置的GC 实现,各种可用的收集器最终满足不同的需求,即使它们的可配置性使得它们的功能相交,有时候更容易维护单独的实现,而不是在现有的GC 实现上堆积另一个配置选项

4)主要用途:

  • 性能测试(可以帮助过滤掉GC引起的性能假象)
  • 内存压力测试(例如,知道测试用例应该不分配超过1GB的内存,我们就可以使用-Xmx1g -XX:+UseEpsilonGC,如果程序有问题,则程序崩溃)
  • 非常短的JOB任务(对象这种任务,接受GC清理堆那都是浪费空间)
  • VM接口测试
  • Last-drop 延迟&吞吐改进

    8.2 ZGC

    ZGC,A Scalable Low-Latency Garbage Collector(Experimental) ZGC应该是JDK11最为瞩目的特性,没有之一,但是它还是实验性的产品,还不建议使用到生产环境上面

1)GC暂停时间不会超过10ms;既能处理几百兆的小堆,也能处理几个T的大堆(OMG);和G1 相比,应用吞吐能力不会下降超过15%;为未来的GC功能和利用colord指针以及Load barriers 优化奠定基础;初始只支持 64 位系统。
2)ZGC的设计目标:支持TB级的内存容量,暂停时间低(<10ms),对整个程序的吞吐量影响小于15%。将来该可以扩展实现机制,以支持不少令人兴奋的功能,例如多层堆(即热对象置于DRAM和冷对象置于NVMe内存),或者压缩堆。
3)GC是Java的主要优势之一,然而,当GC停顿太长时间,就会开始影响应用的响应时间,消除或者减少GC停顿时长,Java将对更广泛的应用场景是一个更有吸引力的平台,此外,现代的系统可用内存在不断的增长,用户和程序员吸引JVM能够以高效的方式充分利用这些内存,并且无需长时间的GC暂停时间。
4)ZGC是一个并发,基于region,压缩型的垃圾收集器,只有 root 扫描阶段会 STW,因此GC 停顿时间不会随着堆的增长和存货对象的增长而变长。