Java基础系列-Java11特性解读

Java11 是 Java8 之后的一个 LTS 版本。Java8 的 LTS 将在今年到期,在 Java8 之后,Java11 就是最好的选择了。Java9 到 Java11 的新特性虽然没有 Java8 的跨度大,但在虚拟机层面有了很大的升级。通过 Benjamin
的这篇博客,我们来看看 Java11 有什么不同。

Java11 的使用率不高,依然有很多的人在生产环境中使用 Java8。这篇文章会使用例子来讲解 Java9 到 Java11 中最重要的新特性。这篇文章使用代码来讲解新特性,不会有大段的文字。

局部变量类型推断

Java 10 中新增了一个关键字 var
,在声明局部变量的时候用 var
就不需要写明具体的数据类型(局部变量是指在 方法
中声明的变量)。

在 Java 10 之前的版本中,你需要这样声明变量:

String text = "Hello Java 9";
复制代码

在 Java 10,可以使用 var
替代 String
编译器会根据变量的赋值去推断变量的类型。在下面这个例子中 text
的类型是 String

var text = "Hello Java 10";
复制代码

通过 var
声明的变量依然是静态类型。不能对已经变量赋值另外一种类型。下面的这段代码会编译不通过:

var text = "Hello Java 11";
text = 23;
复制代码

可以通过 final
来防止声明的 var
变量被重复赋值:

final var text = "Banana";
text = "Joe"; // 编译报错
复制代码

var
变量必须赋值一个明确类型的值,对于没有赋值或者编译器无法推断类型的变量,都会编译错误。下面的代码都无法通过编译:

var a;
var nothing = null;
var lambda = () -> System.out.println("Pity!");
var method = this::someMethod;
复制代码

局部类型推断在处理泛型代码时很好用。在下面的例子中, current
的类型是 Map<String, List<Integer>>
,如果使用 var
来替代 Map<String, List<Integer>>
,就可以少些很多样本代码:

var myList = new ArrayList<Map<String, List<Integer>>>();
for (var current : myList) {
    System.out.println(current);
}
复制代码

在 Java 11 中 var
也可以用于 lambda 的参数,但是需要加上 @Nullable
注解:

Predicate<String> predicate = (@Nullable var a ) -> true;
复制代码

Tip: 在 Intellij IDEA 中,可以通过选中一个变量,同时按下 CMD/CTRL
来显示变量的真实类型(对于键盘党可以使用 CTRL + J
)。

HTTP Client

Java 9
中隐藏一个处理 Http 请求的新 APIHttpClient
。到 Java11
这个 API 已经很完善了,就在 JDK 的 java.net
包下。来看看这个 API 可以做点什么。

这个新的 HttpClient
可以 同步
或者 异步
使用。同步的请求将会阻塞当前线程直到响应返回。 BodyHandlers
定义了期望的返回数据类型。(e.g. 字符串、字节数组或者文件):

var request = HttpRequest.newBuilder()
                   .uri(URI.create("https://winterbe.com"))
                   .GET()
                   .build();
var client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
复制代码

同样的请求也可以进行异步处理。调用 sendAsync
不会阻塞当前线程并且会返回一个 CompleteFuture
来构建一个异步操作的管道。

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

可以省略 .GET()
,默认的请求方法就是这个。

下面的例子通过 POST
方法给一个 URL
发送数据。 BodyHandlers
也可以用来定义请求中需要发送的数据的类型,比如 字符串
字节数组
文件
或者 输入流

var request = HttpRequest.newBuilder()
                   .uri(URI.create("https://postman-echo.com/post"))
                   .header("Content-Type", "text/plain")
                   .POST(HttpRequest.BodyPublishers.ofString("Hi there!"))
                   .build();
var client = HttpClient.newHttpClient();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());      // 200
复制代码

最后的这个例子演示了如何通过 BASIC-AUTH
来进行认证

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://postman-echo.com/basic-auth"))
    .build();
var client = HttpClient.newBuilder()
    .authenticator(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication("postman", "password".toCharArray());
        }
    })
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());      // 200
复制代码

Collections

Java 中的容器比如 List
Set
Map
已经扩展了很多新的方法。 List.of
会根据参数创建一个新的不可变的 list
List.copy
会创建这个 list
的不可变副本。

var list = List.of("A", "B", "C");
var copy = List.copyOf(List);
System.out.println(list == copy); // true
复制代码

因为 list
已经是不可变的,在复制时没必要创建另一个实例,因此 lisi
copy
指向的是同一个实例。然而如果想复制一个可变的对象,就会创建一个新的实例来保证对原对象的修改不会影响到复制的对象。

var list = new ArrayList<String>();
var copy = List.copyOf(list);
System.out.println(list == copy);
复制代码

当创建不可变的 map 时候,不需要手动创建 map 对象,只需要使用 Map.of
方法交替传入 keyvalue 就可以。

var map = Map.of("A", 1, "B", 2);
System.out.println(map);
复制代码

在 Java 11 中不可变容器的 API 没有变化。然而如果尝试对不可变的容器添加或者减少元素,就会抛出 java.lang.UnsupportedOperationException
异常。幸运的是 Intellij IDEA
会在你尝试修改不可变容器的时候发出一个警告。

Streams

Streams
是在 Java8 中加入的新特性,在后面的又加入了 3 个新的方法。 Stream.ofNullable
方法通过单个元素来构造流:

Stream.ofNullable(null)
         .count();  // 0
复制代码

dropWhile
takeWhile
方法都可以接受一个 predicate
参数来决定是否将符合条件的元素从流中清理出去。

predicate 是一个函数式编程的接口

Optionals

Optionals
也接收了一些相当有用的方法。比如现在可以将 optinals 很简单转成 stream 或者为一个空的 optional 返回另一个备用的 optional。

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

Strings

String
这个基础的类也新增了一些方法来校验空格以及计算字符串的行数。

" ".isBlank();                // true
" Foo Bar ".strip();          // "Foo Bar"
" Foo Bar ".stripTrailing();  // " Foo Bar"
" Foo Bar ".stripLeading();   // "Foo Bar "
"Java".repeat(3);             // "JavaJavaJava"
"A/nB/nC".lines().count();    // 3
复制代码

InputStreams

最后简单说一下 InputStream
提供了一个非常有用的方法来传输数据到 OutputStream
,下面这个例子在传输原始数据的时候能经常看到。

var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("myFile.txt");
var tempFile = File.createTempFile("myFileCopy", "txt");
try (var outputStream = new FileOutputStream(tempFile)) {
    inputStream.transferTo(outputStream);
}
复制代码

其他的 JVM 特性

上面的这些事我认为 Java8 到 Java11 中最有趣的新特性。但是新特性远远不止这些。下面的这些特性在最新的 Java 版本中都有:

  • Flow API for reactive programming
  • Java Module System
  • Application Class Data Sharing
  • Dynamic Class-File Constants
  • Java REPL (JShell)
  • Flight Recorder
  • Unicode 10
  • G1: Full Parallel Garbage Collector
  • ZGC: Scalable Low-Latency Garbage Collector
  • Epsilon: No-Op Garbage Collector
  • Deprecate the Nashorn JavaScript Engine

原文 

https://juejin.im/post/5dd0bdd96fb9a02000262307

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Java基础系列-Java11特性解读

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址