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
容器类,如List, Set 和Map 扩展了新的方法。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
dropWhile 和 takeWhile 用于从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);
}