天天看點

Java11新特性及使用

作者:左右為攻

Java 11(2018 年 9 月釋出)包含許多重要且有用的更新。讓我們看看它為開發人員和架構師帶來的新功能和改進。

本文主要内容

  • HTTP用戶端API
  • 無需編譯即可啟動單檔案程式
  • 字元串API更新
  • Collection.toArray
  • Files.readString() 和 Files.writeString()
  • Optional.isEmpty()

1. HTTP用戶端API

Java 使用HttpURLConnection進行HTTP通信已經很長一段時間了。但随着時間的推移,要求變得越來越複雜,應用程式的要求也越來越高。在 Java 11 之前,開發人員不得不求助于功能豐富的庫,如Apache HttpComponents或OkHttp等。

我們看到Java 9釋出包含一個HttpClient實作作為實驗性功能。它随着時間的推移而發展,現在是 Java 11 的最終功能。現在 Java 應用程式可以進行 HTTP 通信,而無需任何外部依賴。

1.1 如何使用HttpClient

java.net.http子產品和典型 HTTP 互動如下所示 :

  • 建立HttpClient的執行個體并根據需要進行配置。
  • 建立一個HttpRequest執行個體并填充資訊。
  • 将請求傳遞給用戶端,執行請求并檢索HttpResponse的執行個體。
  • 處理包含在HttpResponse中的資訊.

HTTP API 可以處理同步和異步通信。讓我們看一個簡單的例子。

1.2 同步請求示例

請注意 http 用戶端 API 如何使用建構器模式來建立複雜對象。

package cn.dayangshuo.http;

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;

public class HttpClientTest {
    public static void main(String[] args) {
        HttpClient httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();
        try {
            String urlEndpoint = "https://www.baidu.com/s";
            URI uri = URI.create(urlEndpoint + "?wd=java11");
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(uri)
                    .build();
            HttpResponse<String> response = httpClient.send(request,
                    HttpResponse.BodyHandlers.ofString());

            System.out.println("Status code: " + response.statusCode());
            System.out.println("Headers: " + response.headers().allValues("content-type"));
            System.out.println("Body: " + response.body());
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}           

1.3 異步請求示例

如果我們不想等待響應,異步通信很有用。我們提供回調處理程式,當響應可用時執行。

注意使用sendAsync()方法發送異步請求。

package cn.dayangshuo.http;

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;

public class HttpClientTest {
    public static void main(String[] args) {
        final List<URI> uris = Stream.of(
                "https://www.baidu.com/",
                "https://www.zhihu.com/people/da-yang-12-48",
                "https://dayangshuo.cn"
        ).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 static 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 源代碼,而無需先編譯它。

編寫一個簡單的HelloWorld.java

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

要執行上述類,請直接使用java指令運作它:

//控制台
$ java HelloWorld.java

Hello World!           

請注意,該程式不能使用任何外部依賴除了使用java.base module子產品化. 并且程式隻能是單檔案程式。

3. 字元串API更新

3.1 String.repeat(Integer)

此方法隻是重複一個字元串n次。它傳回一個字元串,其值為重複 N 次的給定字元串的串聯。

如果此字元串為空或計數為零,則傳回空字元串。

public class HelloWorld {
    public static void main(String[] args) {
      String str = "1".repeat(5);
      //列印出:11111
      System.out.println(str);  
    }
}           

3.2. String.isBlank()

此方法訓示字元串是空的還是僅包含空格。以前,我們一直在用 Apache 的StringUtils.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 ( )僅删除尾字元。

public class HelloWorld {
    public static void main(String[] args) {
      "   hi  ".strip();  //"hi"
      "   hi  ".stripLeading();  //"hi   "
      "   hi  ".stripTrailing(); //"   hi"
    }
}           

3.4. String.lines()

此方法有助于将多行文本作為Stream處理。

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

在 Java 11 之前,将集合轉換為數組并不簡單。Java 11 使轉換更加友善。

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()]);   //Java 11之前
      String[] namesArr2 = names.toArray(String[]::new);          //Java 11
    }
}           

5. Files.readString() 和 Files.writeString()

使用這些重載方法,Java 11 旨在減少大量樣闆代碼,進而更容易讀取和寫入檔案。

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

6. Optional.isEmpty()

Optional是一個容器對象,它可能包含也可能不包含非空值。如果不存在任何值,則該對象被認為是空的。

isPresent()方法如果值存在則傳回true,否則傳回false。

isEmpty()方法與isPresent()方法相反,如果存在值則傳回false,否則傳回true。

是以我們無論如何都不要寫否定條件。适當時使用這兩種方法中的任何一種。

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());
    }
}           

繼續閱讀