原文链接
前言
Java 11(于2018年9月发布)包含许多重要和有用的更新。让我们看看它为开发人员和架构师带来的新特性和改进。
正文
HTTP Client API
Java长期使用HttpURLConnection类进行HTTP通信。但是随着时间的推移,需求变得越来越复杂,对应用程序的要求也越来越高。在Java 11之前,开发人员不得不求助于功能丰富的库,如Apache HttpComponents或OkHttp等。
我们看到Java 9发布版将HttpClient
实现作为一个实验性特性包括在内。它随着时间的推移而发展,现在是Java 11的最后一个特性。现在,Java应用程序可以进行HTTP通信,而不需要任何外部依赖。
如何使用HttpClient
它与java.net.http
模块的经典HTTP通信是类似的:
- 创建一个HttpClient实例,并根据需要配置它。
- 创建HttpRequest实例并填充信息。
- 将请求传递给客户机,执行请求并检索HttpResponse的实例。
- 处理HttpResponse中包含的信息。
HTTP API可以处理同步和异步通信。让我们来看一个简单的例子。
同步请求例子
注意,Http客户端API如何使用builder模式来创建复杂对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; HttpClient httpClient = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .build(); try { String urlEndpoint = "https://postman-echo.com/get"; URI uri = URI.create(urlEndpoint + "?foo1=bar1&foo2=bar2"); HttpRequest request = HttpRequest.newBuilder() .uri(uri) .build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); } System.out.println("Status code: " + response.statusCode()); System.out.println("Headers: " + response.headers().allValues("content-type")); System.out.println("Body: " + response.body());
|
异步请求例子
如果我们不想等待响应,可以使用异步通信。我们提供回调处理程序,它在响应可用时执行。
注意使用sendAsync()
方法发送异步请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; import static java.util.stream.Collectors.toList; final List<URI> uris = Stream.of( "https://www.google.com/", "https://www.github.com/", "https://www.yahoo.com/" ).map(URI::create).collect(toList()); HttpClient httpClient = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .followRedirects(HttpClient.Redirect.ALWAYS) .build(); CompletableFuture[] futures = uris.stream() .map(uri -> verifyUri(httpClient, uri)) .toArray(CompletableFuture[]::new); CompletableFuture.allOf(futures).join(); private CompletableFuture<Void> verifyUri(HttpClient httpClient, URI uri) { HttpRequest request = HttpRequest.newBuilder() .timeout(Duration.ofSeconds(5)) .uri(uri) .build(); return httpClient.sendAsync(request,HttpResponse.BodyHandlers.ofString()) .thenApply(HttpResponse::statusCode) .thenApply(statusCode -> statusCode == 200) .exceptionally(ex -> false) .thenAccept(valid -> { if (valid) { System.out.println("[SUCCESS] Verified " + uri); } else { System.out.println("[FAILURE] Could not " + "verify " + uri); } }); }
|
不用编译运行一个单文件项目
通常,对于我们想要执行的每个程序,我们都需要首先编译它为class文件。对于用于测试的小程序来说,这似乎是一个不必要的冗长过程。
Java 11做出了改变,现在我们可以执行包含在单个文件中的Java源代码,而不需要首先编译它。
HelloWorld.java
1 2 3 4 5
| public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } }
|
要执行上面的类,直接用java
命令运行它。
1 2 3
| $ java HelloWorld.java Hello World!
|
需要注意的是,程序不能使用除java.base
模块之外的任何外部依赖项,并且程序只能是单文件程序。
String API变更
String.repeat(Integer)
这个方法简单地重复一个字符串n次。它返回一个字符串,其值是重复N次的给定字符串的串联。
如果该字符串为空或count为零,则返回空字符串。
1 2 3 4 5 6 7 8 9
| public class HelloWorld { public static void main(String[] args) { String str = "1".repeat(5); System.out.println(str); } }
|
String.isBlank()
此方法判断字符串是否为空或者为空字符串。在此之前,我们一直在使用Apache开源包的StringUtils.java
。
1 2 3 4 5 6 7 8 9 10 11
| public class HelloWorld { public static void main(String[] args) { "1".isBlank(); "".isBlank(); " ".isBlank(); } }
|
String.strip()
此方法负责删除开头和结尾空白。我们可以更具体地使用String.stripLeading()
删除开头空白,或者使用String.stripTrailing()
删除结尾空白。
1 2 3 4 5 6 7 8 9 10 11
| public class HelloWorld { public static void main(String[] args) { " hi ".strip(); " hi ".stripLeading(); " hi ".stripTrailing(); } }
|
String.lines()
这个方法有助于将多行文本处理为一个流。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class HelloWorld { public static void main(String[] args) { String testString = "hello\nworld\nis\nexecuted"; List<String> lines = new ArrayList<>(); testString.lines().forEach(line -> lines.add(line)); assertEquals(List.of("hello", "world", "is", "executed"), lines); } }
|
Collection.toArray(IntFunction)
在Java 11之前,将集合转换为数组并不方便。Java 11使转换更加方便。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class HelloWorld { public static void main(String[] args) { List<String> names = new ArrayList<>(); names.add("alex"); names.add("brian"); names.add("charles"); String[] namesArr1 = names.toArray(new String[names.size()]); String[] namesArr2 = names.toArray(String[]::new); } }
|
Files.readString() 和 Files.writeString()
使用这些重载的方法,Java 11旨在减少大量的样板代码,使文件的读写更加容易。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class HelloWorld { public static void main(String[] args) { URI txtFileUri = getClass().getClassLoader().getResource("helloworld.txt").toURI(); String content = Files.readString(Path.of(txtFileUri),Charset.defaultCharset()); Path tmpFilePath = Path.of(File.createTempFile("tempFile", ".tmp").toURI()); Path returnedFilePath = Files.writeString(tmpFilePath,"Hello World!", Charset.defaultCharset(), StandardOpenOption.WRITE); } }
|
Optional.isEmpty()
Optional是一个容器对象,它可以包含也可以不包含一个非空值。如果没有值,则认为该对象是空的。
如果存在值,则先前存在的方法isPresent()
返回true,否则返回false。有时,它迫使我们写出不方便阅读的判断语句。
isEmpty()
方法与isPresent()
方法相反,如果有值,则返回false,否则返回true。
所以在任何情况下我们都不需要写出相反的条件。在适当的时候使用这两种方法中的任何一种。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class HelloWorld { public static void main(String[] args) { String currentTime = null; assertTrue(!Optional.ofNullable(currentTime).isPresent()); assertTrue(Optional.ofNullable(currentTime).isEmpty()); currentTime = "12:00 PM"; assertFalse(!Optional.ofNullable(currentTime).isPresent()); assertFalse(Optional.ofNullable(currentTime).isEmpty()); } }
|
结语
以上就是关于Java 11 更新的内容。
相关链接: Java 11 release doc