Java 11 教程

1,957 阅读3分钟

Java 11 已经到来,而很多人还在用Java 8,本文涵盖了Java 9 到 11 的重要语法 与API 特性。

本地变量类型接口

Java 10 引进了一个新的关键字 var, var 用于替换声明本地变量时,要为本地变量指定的类型信息,Java 10 以后,我们可以用如下方式声明变量

String text = "Hello Java 9";

我们可以将String 替换为var,编译器会根据我们的赋值,为变量指定特定的类型。在下面的例子中,text 其实是String 类型。

var text = "Hello Java 10";

var 声明变量时,已经有特定的类型了,不能再为其指定其他类型。下面的做法是不对的

var text = "Hello Java 11";
text = 23;  // Incompatible types

我们也可以使用final 关键字修饰var,防止为变量赋其他值

final var text = "Banana";
text = "Joe";   // Cannot assign a value to final variable 'text'

var 不能用于变量类型不明确的情况,如下情况均会出现编译错误:

// Cannot infer type:
var a;
var nothing = null;
var lambda = () -> System.out.println("Pity!");
var method = this::someMethod;

本地变量接口真的非常的好用,在下面的例子中,current 变量的类型为Map<String, List<Integer>>,这个类型可以用var 替换

var myList = new ArrayList<Map<String, List<Integer>>>();

for (var current : myList) {
    // current is infered to type: Map<String, List<Integer>>
    System.out.println(current);
}

Java 11 中,var 也可以在lambda 表达式中使用

Predicate<String> predicate = (@Nullable var a) -> true;

HTTP Client

Java 9 引入了HttpClient 的API 来处理HTTP 请求,在Java 11 中,这个API 在java.net 的包下。

HttpClient 既可以使用异步,又可以使用同步的方式。同步请求会一直阻塞直至当前线程响应返回,BodyHandlers 定义了response body 的类型,如string, byte-array 或者 file。

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,该方法通过返回CompletableFuture 来执行异步操作。

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

下面的例子是通过POST 方法发送数据,我们可以使用BodyPublishers 来定义我们想要发送数据的类型,如 strings, byte-arrays, files 或者 input-streams。

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 认证方式的HTTP 请求

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

容器类,如ListSetMap 扩展了新的方法。List.of 根据给定的参数创建不可修改的列表, List.copyOf 根据给定列表创建列表的拷贝,且列表的拷贝不可修改。

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

在上面的例子中,由于list 已经是不能修改的了,所以没有必要再创建它的一份拷贝,此时,list 和copy 是相等的。然而,如果你创建的是一个可修改的list 的拷贝,那他们就是不相等的。

var list = new ArrayList<String>();
var copy = List.copyOf(list);
System.out.println(list == copy);   // false

当创建不可修改的map 时,你可以通过如下方式

var map = Map.of("A", 1, "B", 2);
System.out.println(map);    // {B=2, A=1}

Immutable collections in Java 11 still use the same interfaces from the old Collection API. However if you try to modify an immutable collection by adding or removing elements, a java.lang.UnsupportedOperationException is thrown. Luckily Intellij IDEA warns via an inspection if you try to mutate immutable collections.

Streams

Streams 是在Java 8中引入的,现在我们又收获了三个新的方法,分别为Stream.ofNullable 通过单个元素构造一个stream。

Stream.ofNullable(null)
    .count()   // 0

dropWhiletakeWhile 用于从stream 中过滤元素。

Stream.of(1, 2, 3, 2, 1)
    .dropWhile(n -> n < 3)
    .collect(Collectors.toList());  // [3, 2, 1]

Stream.of(1, 2, 3, 2, 1)
    .takeWhile(n -> n < 3)
    .collect(Collectors.toList());  // [1, 2]

Strings

Strings 新增了一些方法用于校验空格、去空格、计算行数。

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

参考:winterbe.com/posts/2018/…