还在用着Java 8吗?09月26日Oracle的长期支持版Java 11已经出炉,将一直支持到2026年9月。对广大的程序员们来说,从Java 9~11,日常的编码都有什么变化呢?一起来看看吧。
var关键字
Java 10引进了关键字来指代任意类型,让它朝C#又迈进了一步。以下是两个例子:
var abc =newArrayList();
for(var character : abc) {
}
并不仅仅能类型推断,它还能完成以前做不到的事——引用匿名类的变量:
在所有可能的地方都用上也许并不是一个好实践。一种做法是:如果后面的表达式一眼就能看出来是啥类型,我们就用;否则,就还是老老实实地写声明,一眼扫过就能明白的代码更具可读性。
集合字面量
一直以来我们都是老老实实地用以下这些方法来初始化一个已知的不可变集合:
// 这样挺方便,就是语义上稍欠优雅
List abc1 = Arrays.asList("A","B","C");
// 这样构建的是Collection,可以传入可变集合
Collection abc2 = Collections.unmodifiableCollection(abc1);
// 更优雅的Guava方案
List abc3 = ImmutableList.of("A","B","C");
可变集合:
// 最基本的方法,就是有点长,令人不爽
List abc4 =newArrayList();
abc4.add("A");
abc4.add("B");
abc4.add("C");
// 构造函数
List abc5 =newArrayList(Arrays.asList("A","B","C"));
// 匿名内部类
List abc6 =newArrayList(){{ add("A");add("B");add("C"); }}
// 利用Java 8的Stream
List abc7 = Stream.of("A","B","C").collect(Collectors.toList());
// 更优雅的Guava方案
List abc8 = Lists.newArrayList("A","B","C");
对于不可变集合,Java 9引入了集合的工厂方法,这回终于可以用上原装的了:
List abc1 = List.of("A","B","C");
Set abc2 = Set.of("A","B","C");
Map abc3 = Map.of("A",1,"B",2,"C",3);
Map abc4 = Map.ofEntries(Map.entry("A",1),
Map.entry("B",2),
Map.entry("C",3));
值得注意的是,不允许通过传入,不允许传入相同的键。
List.of("A",null);// NullPointerException
Map.of("A",1,"A",2);// IllegalArgumentException: duplicate key: A
Java 10引入了方法,也能方便地从可变集合中创建出不可变集合:
var abcMutable = new ArrayList(List.of("A", "B", "C"))
var abcImmutable = List.copyOf(abcMutable);
Java 10还在类中增加了//方法,可以直接从创建一个不可变集合:
List abc = Stream.of("A", "B", "C").collect(Collectors.toUnmodifiableList());
Deprecated
这个相对简单,就是给注解增加了两个字段:
@Deprecated(since="1.1", forRemoval = true)
前者表示从哪个版本起不建议使用,后者表示未来是否会将其删除。
接口的private方法
从Java 8起,允许给接口增加方法。从Java 9起,接口又增加了一项能力:可以定义方法了。示例如下:
既然如此,它跟抽象类还有什么区别吗?接口的优势就是允许子类实现多个接口,而抽象类因为可以拥有可变字段(接口的字段是的)而更为强大。我们在接口定义方法时,也应当让其尽可能简洁。
Optional的新方法
从Java 9起,终于可以通过方法返回一个了,这样它就可以用上提供的许多API了。原来只能这么做:
Optional optional = Optional.of("ggg");
// java 8
Stream texts = optional.map(Stream::of).orElseGet(Stream::empty);
// java 9
Stream texts = optional.stream();
另一个可以耍耍的方法是:
// java 8
if (optional.isPresent()) {
System.out.print(optional.get());
} else {
System.out.println();
}
// java 9
optional.ifPresentOrElse(System.out::print, System.out::println);
Java 9还新增了一个方法,与原来的类似,但是返回的是一个:
// java 8
String name = optional.orElse("n/a");
// java 9
Optional name = optional.or(() -> Optional.of("n/a"));
HttpClient
Java 11引进了HttpClient,http请求变得简单了:
异步也很简单,返回一个:
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(uri)).build();
CompletableFuture futureResponse = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
futureResponse.get();
原生的可以抛弃了。Apache的也许也可以雪藏了。
可过期的CompletableFuture
上一小节中,我们可以得到一个。从Java 9起,它可以设置过期时间了。可以把上面的替换如下:
CompletableFuture timeoutFuture = futureResponse.orTimeout(1, TimeUnit.SECONDS);
timeoutFuture.get();
如果没有在设置的时间内获得结果,便会抛出。如果想在过期时不抛异常而是设一个默认值,可以这样做:
CompletableFuture futureResponse = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
CompletableFuture timeoutFuture = futureResponse.completeOnTimeout("default value",1, TimeUnit.MILLISECONDS);
timeoutFuture.get();
Process API
Process API是元老级的API了,但是功能一直不够完整,无法获取进程的PID、用户、命令等。Java 9引入了,可以查询进程,甚至允许在进程退出时执行方法。它提供了获取当前进程的方法,以及获取全部进程的方法。用法如下:
如果在Mac中打开了一个,便可以看到类似这样的输出结果:1234 Optional[/Applications/TextEdit.app/Contents/MacOS/TextEdit]。Windows的话可以打开,也能看到:1234 Optional[C:\Windows\System32\notepad.exe]。可以用以下方法在该进程退出时打印一些信息:
甚至还能用来摧毁进程。如此这般,Java外部打开的或都会被退出。由于其它用户的进程无法使用来获取,所以只能杀掉自己的进程。对安全方面感兴趣的话可以参考一下官方文档。
领取专属 10元无门槛券
私享最新 技术干货