# Java 11 的新特性和增强特性

> 原文： [https://howtodoinjava.com/java11/features-enhancements/](https://howtodoinjava.com/java11/features-enhancements/)

Java 11（于 2018 年 9 月发布）包含许多重要且有用的更新。 让我们看看它为开发人员和建筑师带来的新特性和改进。

## 1\. HTTP 客户端 API

Java 长时间使用`HttpURLConnection`类进行 HTTP 通信。 但是随着时间的流逝，要求变得越来越复杂，对应用程序的要求也越来越高。 在 Java 11 之前，开发人员不得不诉诸特性丰富的库，例如 *Apache HttpComponents* 或 *OkHttp* 等。

我们看到 [Java 9](https://howtodoinjava.com/java9/java9-new-features-enhancements/) 版本包含`HttpClient`实现作为实验特性。 随着时间的流逝，它已经成为 Java 11 的最终特性。现在，Java 应用程序可以进行 HTTP 通信，而无需任何外部依赖。

#### 1.1 如何使用`HttpClient`

与`java.net.http`模块的典型 HTTP 交互看起来像：

*   创建`HttpClient`的实例，并根据需要对其进行配置。
*   创建`HttpRequest`的实例并填充信息。
*   将请求传递给客户端，执行请求，并检索`HttpResponse`的实例。
*   处理`HttpResponse`中包含的信息。

HTTP API 可以处理同步和异步通信。 让我们来看一个简单的例子。

#### 1.2 同步请求示例

请注意，http 客户端 API 如何使用**构建器模式**创建复杂的对象。

```java
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()); 

```

#### 1.2 异步请求示例

如果我们不想等待响应，那么异步通信很有用。 我们提供了回调处理程序，可在响应可用时执行。

注意使用`sendAsync()`方法发送异步请求。

```java
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);
			                }
			            });                                    
}

```

## 2\. 启动不编译的单文件程序

传统上，对于我们要执行的每个程序，我们都需要先对其进行编译。 出于测试目的，小型程序似乎不必要地耗时。

Java 11 对其进行了更改，现在我们可以执行单个文件中包含的 Java 源代码，而无需先对其进行编译。

```java
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

```

要执行上述类，请直接使用`java`命令运行它。

```java
$ java HelloWorld.java

Hello World!

```

> 注意，程序**不能使用`java.base module`之外的任何外部依赖项**。 并且该程序只能是**单文件程序**。

## 3\. 字符串 API 的更改

#### 3.1 `String.repeat(int)`

此方法仅重复[字符串](https://howtodoinjava.com/java-string/)`n`次。 它返回一个字符串，其值是重复 N 次给定字符串的连接。

如果此字符串为空或`count`为零，则返回空字符串。

```java
public class HelloWorld 
{
    public static void main(String[] args) 
    {
    	String str = "1".repeat(5);

        System.out.println(str);	//11111
    }
}

```

#### 3.2 `String.isBlank()`

此方法指示字符串是空还是仅包含空格。 以前，我们一直在 Apache 的`StringUtils.java`中使用它。

```java
public class HelloWorld 
{
    public static void main(String[] args) 
    {
    	"1".isBlank();	//false

        "".isBlank();	//true

        "    ".isBlank();	//true
    }
}

```

#### 3.3 `String.strip()`

此方法需要除去前导和尾随空白。 通过使用`String.stripLeading()`仅删除开头字符，或者使用`String.stripTrailing()`仅删除结尾字符，我们甚至可以更加具体。

```java
public class HelloWorld 
{
    public static void main(String[] args) 
    {
    	"   hi  ".strip();	//"hi"

       "   hi  ".stripLeading();	//"hi   "

       "   hi  ".stripTrailing();	//"   hi"
    }
}

```

#### 3.4 `String.lines()`

此方法有助于将多行文本作为[**流**](https://howtodoinjava.com/java8/java-streams-by-examples/)来处理。

```java
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);
    }
}

```

## 4\. `Collection.toArray(IntFunction)`

在 Java 11 之前，将集合转换为数组并不容易。 Java 11 使转换更加方便。

```java
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()]);		//Before Java 11

	    String[] namesArr2 = names.toArray(String[]::new);					//Since Java 11
    }
}

```

## 5\. `Files.readString()`和`Files.writeString()`

使用这些重载方法，Java 11 的目标是减少大量样板代码，从而使文件读写更加容易。

```java
public class HelloWorld 
{
    public static void main(String[] args) 
    {
    	//Read file as string
    	URI txtFileUri = getClass().getClassLoader().getResource("helloworld.txt").toURI();

    	String content = Files.readString(Path.of(txtFileUri),Charset.defaultCharset());

    	//Write string to file
    	Path tmpFilePath = Path.of(File.createTempFile("tempFile", ".tmp").toURI());

    	Path returnedFilePath = Files.writeString(tmpFilePath,"Hello World!", 
    								Charset.defaultCharset(), StandardOpenOption.WRITE);
    }
}

```

## 6\. `Optional.isEmpty()`

[`Optional`](https://howtodoinjava.com/java8/java-8-optionals-complete-reference/)是一个容器对象，可能包含也可能不包含非`null`值。 如果不存在任何值，则该对象被认为是空的。

如果存在值，则先前存在的方法`isPresent()`返回`true`，否则返回`false`。 有时，它迫使我们编写不可读的负面条件。

`isEmpty()`方法与`isPresent()`方法相反，如果存在值，则返回`false`，否则返回`true`。

因此，在任何情况下我们都不会写负面条件。 适当时使用这两种方法中的任何一种。

```java
public class HelloWorld 
{
    public static void main(String[] args) 
    {
    	String currentTime = null;

	    assertTrue(!Optional.ofNullable(currentTime).isPresent());	//It's negative condition
	    assertTrue(Optional.ofNullable(currentTime).isEmpty());		//Write it like this

	    currentTime = "12:00 PM";

	    assertFalse(!Optional.ofNullable(currentTime).isPresent());	//It's negative condition
	    assertFalse(Optional.ofNullable(currentTime).isEmpty());	//Write it like this
    }
}

```

向我提供有关 Java 11 中这些**新 API 更改的问题**。

学习愉快！

参考： [Java 11 发行文档](https://docs.oracle.com/en/java/javase/11/)