惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
D
Docker
GbyAI
GbyAI
B
Blog RSS Feed
博客园 - 司徒正美
博客园 - Franky
美团技术团队
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
aimingoo的专栏
aimingoo的专栏
C
Check Point Blog
IT之家
IT之家
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
www.infosecurity-magazine.com
www.infosecurity-magazine.com
AI
AI
O
OpenAI News
Attack and Defense Labs
Attack and Defense Labs
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
S
Secure Thoughts
博客园 - 聂微东
L
LINUX DO - 最新话题
U
Unit 42
SecWiki News
SecWiki News
A
Arctic Wolf
Schneier on Security
Schneier on Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Visual Studio Blog
量子位
The Cloudflare Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
大猫的无限游戏
大猫的无限游戏
Google DeepMind News
Google DeepMind News
G
Google Developers Blog
T
Threat Research - Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
B
Blog
博客园 - 【当耐特】
C
CERT Recently Published Vulnerability Notes
Scott Helme
Scott Helme
Last Week in AI
Last Week in AI
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
A
About on SuperTechFans
博客园 - 三生石上(FineUI控件)
Latest news
Latest news

懒程序员改变世界

AI时代的站会:从同步到异步 真实流量,本地回放:一种轻量的性能测试思路 AI编程成熟度模型:从3倍到10倍的路径 用AWS创建工作流 未来的软件开发什么样 手稿秒变html的Sketch 2 Code 组合型软件架构 用JaVers比较对象 逆向工作法 挖掘IntelliJ IDEA的调试功能 软件开发有没有高下 挖掘IntelliJ IDEA的实用功能 敲最少的键,编最多的码 个人的技术债 《Java函数式编程》出版啦 懒程序员笔记 SSH妙用 用Tampermonkey实现自动化网页操作 代码还是数据
Java 11时代,这些编程习惯可以改一改了
Qinghua Gao · 2018-10-14 · via 懒程序员改变世界

还在用着Java 8吗?09月26日Oracle的长期支持版Java 11已经出炉,将一直支持到2026年9月。对广大的程序员们来说,从Java 9~11,日常的编码都有什么变化呢?一起来看看吧。

var关键字

Java 10引进了var关键字来指代任意类型,让它朝C#又迈进了一步。以下是两个例子:

1
2
3
var abc = new ArrayList();
for (var character : abc) {
}

var并不仅仅能类型推断,它还能完成以前做不到的事——引用匿名类的变量:

1
2
3
4
var o = new Object() {
int a = 1;
};
System.out.println(o.a);

在所有可能的地方都用上var也许并不是一个好实践。一种做法是:如果后面的表达式一眼就能看出来是啥类型,我们就用var;否则,就还是老老实实地写声明,一眼扫过就能明白的代码更具可读性。

更详细的用法请参考Oracle官方文档。Java 11更是允许对lambda的参数使用var

集合字面量

一直以来我们都是老老实实地用以下这些方法来初始化一个已知的不可变集合:

1
2
3
4
5
6
7
8

List abc1 = Arrays.asList("A", "B", "C");


Collection abc2 = Collections.unmodifiableCollection(abc1);


List abc3 = ImmutableList.of("A", "B", "C");

可变集合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

List abc4 = new ArrayList<>();
abc4.add("A");
abc4.add("B");
abc4.add("C");


List abc5 = new ArrayList<>(Arrays.asList("A", "B", "C"));


List abc6 = new ArrayList<>(){{ add("A");add("B");add("C"); }}


List abc7 = Stream.of("A", "B", "C").collect(Collectors.toList());


List abc8 = Lists.newArrayList("A", "B", "C");

对于不可变集合,Java 9引入了集合的工厂方法of,这回终于可以用上原装的了:

1
2
3
4
5
6
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传入nullMap不允许传入相同的键。

1
2
List.of("A", null); 
Map.of("A", 1, "A", 2);

Java 10引入了copyOf方法,也能方便地从可变集合中创建出不可变集合:

1
2
var abcMutable = new ArrayList<>(List.of("A", "B", "C"))
var abcImmutable = List.copyOf(abcMutable);

Java 10还在Collectors类中增加了toUnmodifiableList/toUnmodifiableMap/toUnmodifiableSet方法,可以直接从Stream创建一个不可变集合:

1
List abc = Stream.of("A", "B", "C").collect(Collectors.toUnmodifiableList());

Deprecated

这个相对简单,就是给@Deprecated注解增加了两个字段:

1
@Deprecated(since="1.1", forRemoval = true)

前者表示从哪个版本起不建议使用,后者表示未来是否会将其删除。

接口的private方法

从Java 8起,允许给接口增加default方法。从Java 9起,接口又增加了一项能力:可以定义private方法了。示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Dog {
default void bark() {
System.out.println("bowwow");
wagTail();
}

default void walk() {
System.out.println("walk");
wagTail();
}

private void wagTail() {
System.out.println("wag");
}
}

既然如此,它跟抽象类还有什么区别吗?接口的优势就是允许子类实现多个接口,而抽象类因为可以拥有可变字段(接口的字段是final的)而更为强大。我们在接口定义方法时,也应当让其尽可能简洁。

Optional的新方法

从Java 9起,Optional终于可以通过stream()方法返回一个Stream了,这样它就可以用上Stream提供的许多API了。原来只能这么做:

1
2
3
4
5
6
7
Optional optional = Optional.of("ggg");


Stream texts = optional.map(Stream::of).orElseGet(Stream::empty);


Stream texts = optional.stream();

另一个可以耍耍的方法是ifPresentOrElse

1
2
3
4
5
6
7
8
9

if (optional.isPresent()) {
System.out.print(optional.get());
} else {
System.out.println();
}


optional.ifPresentOrElse(System.out::print, System.out::println);

Java 9还新增了一个方法or,与原来的orElse类似,但是返回的是一个Optional

1
2
3
4
5

String name = optional.orElse("n/a");


Optional name = optional.or(() -> Optional.of("n/a"));

HttpClient

Java 11引进了HttpClient,http请求变得简单了:

1
2
3
4
5
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(uri)).build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());

System.out.println(response.body());

异步也很简单,返回一个CompletableFuture

1
2
3
4
5
6
7
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();

原生的HttpURLConnection可以抛弃了。Apache的HttpClient也许也可以雪藏了。

可过期的CompletableFuture

上一小节中,我们可以得到一个CompletableFuture。从Java 9起,它可以设置过期时间了。可以把上面的futureResponse.get()替换如下:

1
2
CompletableFuture timeoutFuture = futureResponse.orTimeout(1, TimeUnit.SECONDS);
timeoutFuture.get();

如果没有在设置的时间内获得结果,便会抛出java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException。如果想在过期时不抛异常而是设一个默认值,可以这样做:

1
2
3
4
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引入了ProcessHandle,可以查询进程,甚至允许在进程退出时执行方法。它提供了获取当前进程的current方法,以及获取全部进程的allProcesses方法。用法如下:

1
2
3
4
Optional currentUser = ProcessHandle.current().info().user();
ProcessHandle.allProcesses()
.filter(p -> p.info().user().equals(currentUser))
.forEach(p -> System.out.println(String.valueOf(p.pid()) + " " + p.info().command()));

如果在Mac中打开了一个TextEdit,便可以看到类似这样的输出结果:1234 Optional[/Applications/TextEdit.app/Contents/MacOS/TextEdit]。Windows的话可以打开notepad.exe,也能看到:1234 Optional[C:\Windows\System32\notepad.exe]。可以用以下方法在该进程退出时打印一些信息:

1
2
3
4
Optional optionalProcessHandle = ProcessHandle.of(1234);
CompletableFuture future = optionalProcessHandle.get()
.onExit().thenAccept(x -> System.out.println(x.pid()));
future.get();

甚至还能用optionalProcessHandle.get().destroy()来摧毁进程。如此这般,Java外部打开的TextEditnotepad.exe都会被退出。由于其它用户的进程无法使用ProcessHandle.of来获取,所以只能杀掉自己的进程。对安全方面感兴趣的话可以参考一下官方文档