Java11新特性一览

2年前 (2022) 程序员胖胖胖虎阿
402 0 0

Java 11是自Java 8以来的又一个LTS版本,是目前全球使用最多的LTS版本之一。下边我们看一下JAVA11的新特性

字符串API增强

在Java 11中,针对String的操作进一步得到加强。避免我们在很常见的场景中引入额外的、复杂的API。

isBlank()
用来判断字符串是不是空字符"“或者trim()之后(” ")为空字符:


 String blankStr = "    ";
 // true
 boolean trueVal = blankStr.isBlank();

lines()
将一个字符串按照行终止符(换行符\n或者回车符\r)进行分割,并将分割为Stream流:

         String newStr = "Hello Java 11 \n felord.cn \r 2021-09-28";
 ​
         Stream<String> lines = newStr.lines();
         lines.forEach(System.out::println);
// Hello Java 11 
 // 张三李四周吴郑王 
 // 2022-18-44

strip()
去除字符串前后的“全角和半角”空白字符:

 String str = "HELLO\u3000";
 // str = 6
 System.out.println("str = " + str.length());
 // trim = 6
 System.out.println("trim = " + str.trim().length());
 // strip = 5
 System.out.println("strip = " + str.strip().length());

从上面也看出来了差别,trim()只能去除半角空白符。
strip()方法还有两个变种,stripLeading()用来去除前面的全角半角空白符;stripTrailing()用来去除尾部的全角半角空白符。

repeat(n)
按照给定的次数重复串联字符串的内容:

 String str = "HELLO";
 // 空字符
 String empty = str.repeat(0);
 // HELLO
 String repeatOne = str.repeat(1);
 // HELLOHELLO
 String repeatTwo = str.repeat(2);

集合转对应类型的数组
之前想集合转对应的数组很麻烦,要么用迭代;要么用Stream流,现在你可以这样:

         List<String> sampleList = Arrays.asList("张三", "java 11");
         // array = {"张三", "java 11"};
         String[] array = sampleList.toArray(String[]::new);

断言取反
java.util.function.Predicate是我们很常用的断言谓词函数。在以前取反我们得借助于!符号,到了Java 11我们可以借助于其静态方法not来实现,这样语义就更加清晰了:

      List<String> sampleList = Arrays.asList("张三", "java 11","jack");
        // [jack]
        List<String> result = sampleList.stream()
                // 过滤以j开头的字符串
                .filter(s -> s.startsWith("j"))
                // 同时不包含11的字符串
                .filter(Predicate.not(s -> s.contains("11")))
                .collect(Collectors.toList());

var可以用于修饰Lambda局部变量
在Java 10中引入的var来进行类型推断。在Java 10中它不能用于修饰Lambda表达式的入参,其实对于一个Lambda表达式来说它入参的类型其实是可以根据上下文推断出来的。拿上面的例子来说,s -> s.startsWith(“j”)中的s肯定是字符串类型,因此在Java 11中var可以用于修饰Lambda局部变量:

   List<String> sampleList = Arrays.asList("张三", "java 11","jack");
        List<String> result = sampleList.stream()
                // 过滤以j开头的字符串
                .filter((@NotNull var s) -> s.startsWith("j"))
                // 同时不包含11的字符串
                .filter(Predicate.not((@NotNull var s) -> s.contains("11")))
                .collect(Collectors.toList());

如果我们不声明var就没有办法为输入参数添加@NotNull注解。

文件中读写字符串内容更方便
Java 11中可以更轻松地从文件中读取和写入字符串内容了,我们可以通过Files工具类提供的新的静态方法readString和writeString分别进行读写文件的字符串内容,放在之前老麻烦了,特别是对IO流不熟悉的同学来说。现在简单几行就搞定了:

        String dir= "C://yourDir/hello.txt";
// 写入文件
        Path path = Files.writeString(Path.of(dir), "hello java 11");
// 读取文件
            String fileContent = Files.readString(path);
            // hello java 11
        System.err.println(fileContent);

嵌套类的访问控制规则
Java 11之前,内部嵌套类访问外部类的私有属性和方法是可行的:

public class Outer {
    private int outerInt;

     class Inner {
       public void printOuterField() {
         System.out.println("Outer field = " + outerInt);
       }
    }
}

但是如果你通过反射API实现内部类访问外部类的私有属性和方法就会抛出IllegalStateException异常。Java 11 修复了反射不能访问的问题.

JVM 访问规则不允许嵌套类之间进行私有访问。我们能通过常规方式可以访问是因为 JVM 在编译时为我们隐式地创建了桥接方法。Java 11 中引入了两个新的属性:一个叫做 NestMembers 的属性,用于标识其它已知的静态 nest 成员;另外一个是每个 nest 成员都包含的 NestHost 属性,用于标识出它的 nest 宿主类。在编译期就映射了双方的寄宿关系,不再需要桥接了。

HttpClient支持HTTP2
Java 9 引入了一个新的酝酿中的 HttpClient API 来处理 HTTP 请求。从 Java 11开始,这个API 现在是最终版本,可以在标准库包 java.net 中使用。让我们来实验一下这个 API 能做些什么。


        var request = HttpRequest.newBuilder()
                .uri(URI.create("https://baidu.com"))
                .GET()
                .build();
        var client = HttpClient.newHttpClient();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
// <html>
// <head><title>302 Found</title></head>
// <body bgcolor="white">
// <center><h1>302 Found</h1></center>
// <hr><center>bfe/1.0.8.18</center>
// </body>
// </html>

同样的请求可以异步执行。调用 sendAsync 不会阻塞当前线程,而是返回一个CompletableFuture 来构建异步操作管道。

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://baidu.com"))
    .build();
var client = HttpClient.newHttpClient();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
    .thenApply(HttpResponse::body)
    .thenAccept(System.out::println);

数据流 Streams
流是在 Java 8 中引入的,现在增加了三个新方法。Stream.ofNullable 从单个元素构造流:

Stream.ofNullable(null)
    .count()   // 0

dropWhile 和 takeWhile 方法都接受一个谓词来决定从流中放弃或选用哪些元素

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

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

Optionals
Optionals 增加了非常方便的新方法,例如,你现在可以简单地将 Optionals 转换为流,或者提供另一个 Optionals 作为空 Optionals 的回调

Optional.of("foo").orElseThrow();     // foo
Optional.of("foo").stream().count();  // 1
Optional.ofNullable(null)
    .or(() -> Optional.of("fallback"))
    .get();     

Epsilon垃圾收集器
JDK上对这个特性的描述是:开发一个处理内存分配但不实现任何实际内存回收机制的GC,一旦可用堆内存用完,JVM就会退出。我们可以来尝试着使用一下它,首先我们编写一段程序:

public class EpsilonTest {
    public static void main(String[] args) throws Exception {
        var list = new ArrayList<>();
        boolean flag = true;
        int count = 0;
        while (flag) {
            list.add(new Garbage());
            if (count++ == 500) {
                list.clear();
            }
        }
    }
}

class Garbage {
    private double d1 = 1;
    private double d2 = 2;

    /**
     * GC在清除本对象时会调用该方法
     */
    @Override
    protected void finalize() throws Throwable {
        System.out.println(this + " collecting");
    }
}

这是一个无限循环的程序,循环体不断创建Garbage对象并放入集合,当循环次数达到500时将集合清空,此时的500个对象均为垃圾,会被GC清理,清理时调用finalize()方法打印信息。运行这段程序,结果如下:

...
com.itcast.Garbage@1e9c634c collecting
java.lang.OutOfMemoryError: Java heap space
    at com.itcast.EpsilonTest.main(EpsilonTest.java:11)
com.itcast.Garbage@1174213e collecting
com.itcast.Garbage@2029a4b8 collecting
...

当程序执行到某一刻时,内存溢出,程序终止。现在我们来使用一下Epsilon,启动参数: UnlockExperimentalVMOptions:解锁隐藏的虚拟机参数。

-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xms100m -Xmx100m

运行程序后,结果如下:

程序开始
Terminating due to java.lang.OutOfMemoryError: Java heap space

会发现,控制台只输出了这么一句,说明被清除的集合中的对象并没有被回收,而且内存溢出的速度也非常快,这说明该GC是并不会回收垃圾,那么它有什么作用呢?它提供完全被动的GC实现,具有有限的分配限制和尽可能低的延迟开销,但代价是内存占用和内存吞吐量,它的主要用途有以下几个方面:

  • 性能测试(它可以帮助过滤掉GC引起的性能假象)
  • 内存压力测试
  • 非常短的JOB任务
  • VM接口测试

ZGC垃圾回收器
据说这是JDK11最为瞩目的特性,没有之一,是最重磅的升级,那么ZGC的优势在哪里呢?

  • GC暂停时间不会超过10毫秒
  • 既能处理几百兆的小堆,也能处理几个T的大堆
  • 和G1相比,应用吞吐能力不会下降超过15%
  • 为未来的GC功能和利用colord指针以及Load barriers优化奠定了基础

ZGC是一个并发、基于region、压缩型的垃圾收集器,只有root扫描阶段会STW(strop the world,停止所有线程),因此ZGC的停顿时间不会随着堆的增长和存活对象的增长而变长。用法:-XX:UnlockExperimentalVMOptions -XX:+UseZGC虽然功能如此强大,但很遗憾的是,在Windows系统的JDK中并没有提供ZGC,所以也就没有办法测试了

版权声明:程序员胖胖胖虎阿 发表于 2022年9月4日 下午5:24。
转载请注明:Java11新特性一览 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...