文章目录
  1. 1. 1.集合工厂方法
  2. 2. 2.私有接口方法
  3. 3. 3.改进的进程 API
  4. 4. 4. 改进的 Stream API
  5. 5. 5. 改进的 try-with-resources
  6. 6. 6. 改进的 Optional 类
    1. 6.1. stream()
    2. 6.2. ifPresentOrElse
    3. 6.3. orElse
  7. 7. 7. 改进的 CompletableFuture API
  8. 8. 8. 支持使用var
    1. 8.1. 9. 删除的内容
  9. 9. 10. 字符串API加强
    1. 9.1. isBlank()
    2. 9.2. lines()
    3. 9.3. strip()
    4. 9.4. repeat
    5. 9.5. indent
    6. 9.6. formatted
  10. 10. 11. 多行字符串
  11. 11. 12. 文本转义
  12. 12. 13. 文件读写更方便
  13. 13. 14. HttpClient
  14. 14. 15. switch表达式改进
  15. 15. 16. NumberFormat
  16. 16. 17. instanceof
  17. 17. 18. record
  18. 18. 19. sealed class 密封类
  19. 19. 其它更新
  20. 20. 官方参考

1.集合工厂方法

从Java 9开始, List,Set 和 Map 接口中,新的静态工厂方法可以创建这些集合的不可变实例。方便创建简单列表

代码示例:

1
2
3
4
5
6
7
8
public static void main(String[] args){
List<String> list = List.of("a","b","c");
System.out.println(list);
Set<String> set = Set.of("a", "b", "c");
System.out.println(set);
Map<String, String> map = Map.of("k1","v1","k2","v2","k3","v3");
System.out.println(map);
}

输出结果

1
2
3
[a, b, c]
[a, b, c]
{k1=v1, k2=v2, k3=v3}

2.私有接口方法

在Java 8,接口可以有常量变量和抽象方法。我们不能在接口中提供私有方法的实现。现在接口越来越象抽象类了,意味着java通过这种方式变相的实现多继承。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface MyInterface {
private void test(){
System.out.println("private test method");
}
default void doTest(){
test();
}
public static void main(String[] args){
MyInterface myinterface = new MyInterface() {

};
myinterface.doTest();
}
}

关键点:可以在 接口中使用 private 来定义私有接口

3.改进的进程 API

在 Java 9 之前,Process API 仍然缺乏对使用本地进程的基本支持,例如获取进程的 PID 和所有者,进程的开始时间,进程使用了多少 CPU 时间,多少本地进程正在运行等。

Java 9 向 Process API 添加了一个名为 ProcessHandle 的接口来增强 java.lang.Process 类。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) throws IOException {
ProcessBuilder pb = new ProcessBuilder("cmd.exe");
String Null = "Null";
Process p = pb.start();
ProcessHandle.Info info = p.info();
System.out.println("进程ID " + p.pid());
System.out.println("可执行文件 " + info.command().orElse(Null));
System.out.println("启动时间 " + info.startInstant().map(i -> i.atZone(ZoneId.systemDefault())
.toLocalDateTime().toString()).orElse(Null));
System.out.println("参数 " + info.arguments().map(a -> Stream.of(a).collect(
Collectors.joining(" "))).orElse(Null));
System.out.println("用户 " + info.user().orElse(Null));
}

输出:

1
2
3
4
5
进程ID 25420
可执行文件 C:\Windows\System32\cmd.exe
启动时间 2022-10-27T10:35:42.124
参数 Null
用户 admin

4. 改进的 Stream API

Java 9 为 Stream 新增了:dropWhile、takeWhile、ofNullable 方法,iterate 方法新增了一个重载方法。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args){
Stream.of("a","b","c","","e","f").takeWhile(s->!s.isEmpty())
.forEach(System.out::print);
System.out.println("\n===");
Stream.of("a","b","c","","e","f").dropWhile(s-> !s.isEmpty())
.forEach(System.out::print);
System.out.println("\n===");
IntStream.iterate(3, x -> x < 10, x -> x+ 3).forEach(System.out::println);
System.out.println("===");
List list = Stream.ofNullable(null).collect(Collectors.toList());
System.out.println(list.size());
}

输出结果:

1
2
3
4
5
6
7
8
9
abc
===
ef
===
3
6
9
===
0

说明:

  • takeWhile : 满足条件才执行,不满足则退出循环
  • dropWhile : 第一次不满足条件才执行
  • iterate : 方便创建流,可用于测试
  • ofNullable: 防止空指针

5. 改进的 try-with-resources

从java7开始,支持了try-with-resources, 但在java 7 的时候,变量必须定义在try后的括号里。现在可以放出来了,使用更简单 示例代码

1
2
3
4
5
6
7
8
 public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("c:/tmp/b.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("c:/tmp/c.txt"));
try(br;bw){
String line = br.readLine();
bw.write(line);
}
}

6. 改进的 Optional 类

在 Java 9 中, Optional 添加了以下方法:

  • stream()

  • ifPresentOrElse()

  • orElse()

    stream()

    从Optional 中获取一个stream, 如果有值则返回该值的stream, 否则返回一个空的流,Stream.empty()。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args){
Optional op = Optional.empty();
System.out.println(op.stream().toList().size());
Optional op2 = Optional.of("1");
System.out.println(op2.stream().toList().size());

System.out.println("===");
Optional<List<String>> op3 = Optional.of(List.of("1","2"));
op3.stream().forEach(t-> System.out.println(t));
System.out.println(op3.stream().toList().size());
}

输出结果:

1
2
3
4
5
0
1
===
[1, 2]
1

ifPresentOrElse

定义

1
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) 

示例代码:

1
2
3
4
5
6
7
public static void main(String[] args){
Optional<String> op = Optional.of("A");
op.ifPresentOrElse(t->System.out.println(t),()->System.out.println("Empty"));

Optional<String> op1 = Optional.empty();
op1.ifPresentOrElse(t->System.out.println(t),()->System.out.println("Empty"));
}

输出结果

1
2
A
Empty

orElse

如果optional有值,返回对应的值此,否则返回orElse里的内容 定义:

1
public T orElse(T other)

示例代码:

1
2
3
4
5
6
7
public static void main(String[] args){
Optional<String> op = Optional.of("A");
System.out.println(op.orElse("B"));

Optional<String> op1 = Optional.empty();
System.out.println(op1.orElse("B"));
}

输出结果

1
2
A
B

7. 改进的 CompletableFuture API

新增了

  • newIncompleteFuture
  • defaultExecutor
  • copy
  • minimalCompletionStage
  • completeAsync
  • orTimeout
  • completeOnTimeout
  • delayedExecutor
  • completedStage
  • failedFuture
  • failedStage

8. 支持使用var

从 java 10开始,引入了var 来声明局部变量 示例代码:

1
2
3
4
5
6
var str = "Hi";
var v = 0;
for(var i=0;i<10;i++){

}
var list = new ArrayList<String>();

9. 删除的内容

Java 10 删除了很多工具:

  • 命令行工具 javah,可以使用 javac -h 代替。
  • 命令行选项 -X:prof,尽管可以使用 jmap 工具来访问分析信息。

一些从 Java1.2 开始标记的为已弃用的 API 也被永久删除了。包括 java.lang.SecurityManager.inCheck 字段和以下方法:

1
2
3
4
5
6
7
8
9
10
java.lang.SecurityManager.classDepth(java.lang.String)
java.lang.SecurityManager.classLoaderDepth()
java.lang.SecurityManager.currentClassLoader()
java.lang.SecurityManager.currentLoadedClass()
java.lang.SecurityManager.getInCheck()
java.lang.SecurityManager.inClass(java.lang.String)
java.lang.SecurityManager.inClassLoader()
java.lang.Runtime.getLocalizedInputStream(java.io.InputStream)
java.lang.Runtime.getLocalizedOutputStream(java.io.OutputStream)
弃用

整个 SecurityManager 类在 java 17 被标识为 弃用。在将来可能会删除。

JDK 10 也弃用了一些 API。

  • java.security.acl 包已标记为已弃用,也包括 java.security 包中包含各种相关的类(Certificate,Identity,IdentityScope,Singer,auth.Policy)。
  • javax.management.remote.rmi.RMIConnectorServer 类中的 CREDENTIAL_TYPES 被标记为不建议使用。
    • java.io.FileInputStream 和 java.io.FileOutputStream 中的 finalize()方法已被标记为已弃用。所以在 java.util.zip.Deflater / Inflater / ZipFileclasses 中的 finalize()方法也被弃用。

10. 字符串API加强

isBlank()

从java 11 起开始支持,用来判断字符串里是否只包含空字符

定义:

1
public boolean isBlank()

示例代码:

1
2
3
4
public static void main(String[] args){
String s = " ";
System.out.println(s.isBlank());
}

输出结果

1
true

常见的空格,回车,换行,制表符 都会被识别为空白字符。

lines()

定义

1
public Stream<String> lines()

从java 11 起开始支持,按 \r \n 把符串转成stream.

示例代码:

1
2
String str = "a\n b\r\rc";
System.out.println(str.lines().count());

输出结果

1
4

\r\n会只作为一个换行符。连续的 \r\n\r\n 就会识别为两行

strip()

定义

1
public String strip()

从java 11 起开始支持,去掉字符串前后的半角和全角空格,trim()只能去掉半角空格。stripLeading()是去掉左边的空格,stripTrailing()是去掉右边的空格

1
2
3
4
5
6
7
8
9
String str = " Hello\u3000";
// str = 7
System.out.println("str = " + str.length());
// trim = 6
System.out.println("trim = " + str.trim().length());
// strip = 5
System.out.println("strip = " + str.strip().length());
System.out.println("stripLeading[" + str.stripLeading() + "]");
System.out.println("stripTrailing[" + str.stripTrailing() + "]");

输出

1
2
3
4
5
str = 7
trim = 6
strip = 5
stripLeading[HELLO ]
stripTrailing[ HELLO]

repeat

定义

1
public String repeat(int count)

从java 11开始支持,重复当前字符串多次。可以用于日志输出时,输出多个分隔符,比如:======================

1
2
3
String s = "=";
// output ===
System.out.println(s.repeat(3));

indent

定义

1
public String indent(int n) 

从java12开始支持,对字符串的每一行前面加n个空格。当n小于0时,就是去掉n个空格。并且在字符串的最后,会加上换行符。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
String a = "hi";
System.out.println("[" + a.indent(2) + "]");
System.out.println("[" + a.indent(-2) + "]");
System.out.println("-".repeat(10));

String b = " ha";
System.out.println("[" + b.indent(2) + "]");
System.out.println("[" + b.indent(-2) + "]");
System.out.println("-".repeat(10));

String c = " ho";
System.out.println("[" + c.indent(2) + "]");
System.out.println("[" + c.indent(-2) + "]");
System.out.println("-".repeat(10));

String t = "ta\ntb";
System.out.println("[" + t.indent(2) + "]");
System.out.println("[" + t.indent(-2) + "]");

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[  hi
]
[hi
]
----------
[ ha
]
[ha
]
----------
[ ho
]
[ ho
]
----------
[ ta
tb
]
[ta
tb
]

formatted

定义:

1
public String formatted(Object... args)

从java 15开始支持。便于字符串本身就是格式化串时的使用,等价于String.format(this, args)

示例代码:

1
2
String str = "hi %s";
System.out.println(str.formatted("小明"));

输出结果

1
hi 小明

11. 多行字符串

从java 15开始支持多行字符串,String类也增加了配套的方法。

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args){
String str = """
<div>
<h1>多行文本</h1>
<p>java 支持多行文本语法</p>
</div>
""";
System.out.println(str);
System.out.println("_".repeat(30));
System.out.println(str.stripIndent());
System.out.println("_".repeat(30));
}

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
<div>
<h1>多行文本</h1>
<p>java 支持多行文本语法</p>
</div>

______________________________
<div>
<h1>多行文本</h1>
<p>java 支持多行文本语法</p>
</div>

______________________________

java17会自动把多行文本前面的缩进空格去掉。没有必要再用stripIndent()方法重复处理。

12. 文本转义

定义

1
public String translateEscapes()

从java 15开始支持,把字符串里的\n变成换行符,其它的\t \r 也同样支持。

示例代码:

1
2
3
String str = "ha\\noo\\tkk";
System.out.println(str);
System.out.println(str.translateEscapes());

输出结果

1
2
3
ha\noo\tkk
ha
oo kk

13. 文件读写更方便

java从1.7开始提供了Files工具类,java 11 增加了 writeString 和 readString,可以更方便的读写文本文件。

定义

1
2
3
4
public static String readString(Path path) throws IOException
public static String readString(Path path, Charset cs) throws IOException
public static Path writeString(Path path, CharSequence csq, OpenOption... options)throws IOException
public static Path writeString(Path path, CharSequence csq, Charset cs, OpenOption... options)throws IOException

默认使用的是UTF-8的编码,示例代码如下

1
2
3
String dir= "C://tmp/hello.txt";
Path path = Files.writeString(Path.of(dir), "java 学习");
String str = Files.readString(path);

java 12 还增加了 mismatch 方法。对比两个文件,如果内容一致,会返回 -1 ,如果内容不同,会返回不同的字节开始位置。

14. HttpClient

java 11 支持了HttpClient, Http请求可以不用再引第三方包了。

1
2
3
4
5
6
7
8
9
 public static void main(String[] args) throws IOException, InterruptedException {
var request = HttpRequest.newBuilder()
.uri(URI.create("https://baidu.com"))
.GET()
.build();
var client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}

15. switch表达式改进

可以把多个case写在一行了,通过 -> 来执行相关动作。

1
2
3
4
5
6
7
8
String month = "june";
switch (month) {
case "march", "april", "may" -> System.out.println("春天");
case "june", "july", "august" -> System.out.println("夏天");
case "september", "october", "november" -> System.out.println("秋天");
case "december", "january", "february" -> System.out.println("冬天");
default -> System.out.println("不知道什么季节");
}

16. NumberFormat

方便输出数字格式化后的显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Locale locale = new Locale("zh", "CN");
NumberFormat numberFormat = NumberFormat.getCompactNumberInstance(locale, NumberFormat.Style.SHORT);

System.out.println(numberFormat.format(100));
System.out.println(numberFormat.format(1000));
System.out.println(numberFormat.format(10000));
System.out.println(numberFormat.format(100000));
System.out.println(numberFormat.format(1000000));

// 设置小数位数
numberFormat.setMaximumFractionDigits(2);
System.out.println(numberFormat.format(1234));
System.out.println(numberFormat.format(123456));
System.out.println(numberFormat.format(12345678));
System.out.println(numberFormat.format(1234567890));

输出内容:

1
2
3
4
5
6
7
8
9
100
1,000
1万
10万
100万
1,234
12.35万
1234.57万
12.35亿

如果把第一行改成美国的Locale

1
Locale locale = new Locale("en", "US");

那么就会输出:

1
2
3
4
5
6
7
8
9
100
1K
10K
100K
1M
1.23K
123.46K
12.35M
1.23B

17. instanceof

java 14 简化了 instanceof 关键字的用法,现在你可以这样写

1
2
3
4
Object obj = "abc";
if(obj instanceof String str){
System.out.println(str);
}

18. record

record关键字,在java 17转正。它是和class, interface, enum 同类的关键字。 我们可以创建一个Point.java文件,里面就写:

1
public record Point(int x,int y) {}

然后就可以这样来使用了

1
2
3
4
5
6
7
8
public class RecordTest {
public static void main(String[] args){
Point p = new Point(1,2);
System.out.println(p.x());
System.out.println(p.y());
System.out.println(p.toString());
}
}

它适用于,简单不可变对象的封装。在某些场景下,可以替代lombok

19. sealed class 密封类

先看代码

1
2
3
4
5
6
public sealed class Person permits Female, Male {
}
public final class Male extends Person{
}
public final class Female extends Person {
}

上面我们定义了三个类,Person, Male 和 Female,即 人,男人,女人。 密封类就是增加了一种可能,明确定义某个类只能被指定的类继承。其它类无法对其进行继承。

从上面的例子我们看到 Person类前面使用了 sealed class 对其进行声明,在后面通过 permits 关键字指定了它只能被Female, Male这两个类进行继承。

Female, Male 这两个类在声明的时候必须指定它是final,还是 sealed ,还是non-sealed。如果指定为non-sealed,那么它就以可以被随意继承了。

看下面的代码:

1
2
3
4
5
6
7
8
9
10
public sealed class Person permits Female, Male {
}
public final class Female extends Person {
}
public sealed class Male extends Person permits OldMale {
}
public non-sealed class OldMale extends Male{
}
public class CityOldMale extends OldMale{
}

这里我们把Male改为sealed修饰的类,指定其唯一子类 OldMale。但在声明 OldMale 指定为 non-sealed, 这么一来 OldMale 就又可以被随意的继承了。比如上面的 CityOldMale。

注意 上面的代码是5个类,我自己测试时是用了5个文件,大家可以自己试试以加深印象。

其它更新

在 Java 11 支持了 Unicode 10 之后, Java 12 支持了 Unicode 11,支持操作更多的表情、符号。

垃圾回收优化,引入 ZGC回收

java 14 移除了CMS(Concurrent Mark Sweep)垃圾收集器

官方参考

文章目录
  1. 1. 1.集合工厂方法
  2. 2. 2.私有接口方法
  3. 3. 3.改进的进程 API
  4. 4. 4. 改进的 Stream API
  5. 5. 5. 改进的 try-with-resources
  6. 6. 6. 改进的 Optional 类
    1. 6.1. stream()
    2. 6.2. ifPresentOrElse
    3. 6.3. orElse
  7. 7. 7. 改进的 CompletableFuture API
  8. 8. 8. 支持使用var
    1. 8.1. 9. 删除的内容
  9. 9. 10. 字符串API加强
    1. 9.1. isBlank()
    2. 9.2. lines()
    3. 9.3. strip()
    4. 9.4. repeat
    5. 9.5. indent
    6. 9.6. formatted
  10. 10. 11. 多行字符串
  11. 11. 12. 文本转义
  12. 12. 13. 文件读写更方便
  13. 13. 14. HttpClient
  14. 14. 15. switch表达式改进
  15. 15. 16. NumberFormat
  16. 16. 17. instanceof
  17. 17. 18. record
  18. 18. 19. sealed class 密封类
  19. 19. 其它更新
  20. 20. 官方参考