1. 人人编程首页
  2. 编程语言
  3. Java

Java 11新特性介绍

Java 11(于2018年9月发布)包含许多重要且有用的更新。让我们看看它为开发人员和架构师带来的新功能和改进

HTTP Client API

Java一直使用JavaHttpURLConnection类用于HTTP通信。但是随着时间的流逝,应用程序的要求越来越复杂。在Java 11之前,开发人员不得不使用一些第三方库,例如Apache HttpComponents或OkHttp等。我们看到Java 9发行版包含一个HttpClient作为实验性功能的实现。随着时间的流逝,它已经成为Java 11的最终功能。现在,Java应用程序可以进行HTTP通信,而无需任何外部依赖。

如何使用HttpClient

这是 Java 9 开始引入的一个处理 HTTP 请求的的孵化 HTTP Client API,该 API 支持同步和异步,而在 Java 11 中已经为正式可用状态,你可以在 java.net 包中找到这个 API。

同步请求示例

注意http client API是如何使用构建者模式创建复杂对象的。

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()方法发送异步请求。

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

一个命令编译运行源代码

传统上,对于我们要执行的每个程序,我们都需要先对其进行编译。出于测试目的,小型程序似乎不需要这么繁琐的操作。
Java 11对其进行了更改,现在我们可以执行单个文件中包含的Java源代码,而无需先对其进行编译。

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

要执行上述类,可直接使用java命令运行它。

$ java HelloWorld.java

Hello World!

需要注意的是该程序除了java.base module之外不能使用任何外部的依赖。并且程序只能是单文件程序。

String 加强

String.repeat(Integer)

repeat() 方法将字符串重复指定次数,如果传递的是负数,则会抛出异常,如果传递的是 0 ,那么就返回空字符串了

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

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

String.isBlank()

isBlank 用于判断字符串是否全部都是空白符,需要注意的是,Java 语言使用 UTF-8 编码,所有 UTF-8 被视为空白符的,在 Java 中也一样

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

        "".isBlank();   //true

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

String.strip()

此方法用于删除字符串头尾的所有空白符,另外可以用stripLeading()删除字符串左边( 头部 )的所有空白符,stripTrailing() 删除字符串右边 ( 尾部 ) 的所有空白符

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

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

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

String.lines()

lines()方法 一次性将字符串按照换行符分割并返回所有行的流

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 9 开始,Jdk 里面为集合(List/ Set/ Map)都添加了 of 和 copyOf 方法,它们两个都用来创建不可变的集合,来看下它们的使用和区别。

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

Files.readString() and Files.writeString()

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

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

Optional.isEmpty()

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

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

InputStream 加强

InputStream 终于有了一个非常有用的方法:transferTo,可以用来将数据直接传输到 OutputStream,这是在处理原始数据流时非常常见的一种用法,如下示例:

var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("javastack.txt");
var javastack = File.createTempFile("javastack2", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
    inputStream.transferTo(outputStream);
}

本文来自转载,原文链接:

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注