有没有感觉到老牌开发语言Java的地位有些摇摇欲坠,这几年一直在奋起直追啊,不断向其它新型语言学习,甚至吸收函数式编程语言的特性,垃圾回收器的性能也是从更强走向更强,生怕落伍啊,让广大码农朋友甚至有了学不过来的感觉,很多项目也还停留在Java 6和8上,很少有项目敢于追上Java的步子。
话说回来,这该学还得学啊,俗话说,作为码农,生是学习的人,死也是学习的鬼,要活到死,学到死,春蚕到死学方完,蜡炬成灰习到头,来快速地浏览一下Java11到17各版本中的新特性吧,看过的再来复习一遍,也许下下个项目就能用上。
Java 11
一条命令直接运行源码文件
从Java 11开始,不用再老套地走“编写-编译-运行”这套流程了,尿急的时候,直接使用java命令就可以运行源码文件啦,尿不湿也省下了。大项目用不上,写个小程序、小脚本还是方便了很多,一下把学python的钱也省下了,又离有女朋友进了一步,不是吗?
java RunMe.java
String又长本事了
曾几何时,Java的String用着是真心地累呀!最常用的判空方法还要引个工具库进来,真想骂人啊。这下好了,光棍版本的Java终于良心发现了,一下子就给String续了4格血,妈妈再也不用担心我掉头发了:
.isBlank— 如果为空或仅包含空格,则返回 true。
.lines— 将字符串转换为由换行符分割后的字符串流。
.strip— 从字符串中删除所有前导和尾随空格。
.repeat — 重复一个字符串 n 次以产生一个新的字符串。
// isBlank
assertTrue("".isBlank());
assertTrue(" ".isBlank());
assertFalse("not blank".isBlank());
// lines
assertEquals(
List.of("hello", "world!"),
"hello\nworld!".lines().collect(Collectors.toList())
);
// strip
assertEquals(
"hello",
" hello ".strip()
);
// repeat
assertEquals(
"echo echo echo ",
"echo ".repeat(3)
);
File也变得潇洒起来
苍天有眼啊,光棍版Java为File类增加了readString和writeString两个方法,可以直接从文件读取和写入String了,简直不要太方便,我只想说,让InputStreams类在这种常见的简单任务中见鬼去吧!
// Files.writeString
Path tempFile = Files.createTempFile(Path.of("target"), "test", ".txt");
Files.writeString(tempFile, "Hello World!");
// Files.readString
String read = Files.readString(tempFile);
assertEquals("Hello World!", read);
Collection也想换个性别
美丽国在搞性别战略,超前的咱们看不懂啊,Collection也耐不住性子了,在光棍版推出了toArray这个方法,想搞个大变活人,集合瞬间就变数组了,这是直接省下了去泰国的手术费啊。
var list = List.of("x", "y", "z");
// toArray
assertArrayEquals(
new String[]{"x", "y", "z"},
list.toArray(String[]::new)
);
Predicate大胆说不
在我们的印象中,Predicate总是唯唯诺诺,连个屁都不敢放,这会也不知是不是继承了他爸的2亩地,开始变得有点不一样了,居然敢说不了(增加了not方法),真是旧社会的农民翻了身啊,不信你看:
Predicate<Boolean> isTrue = (Boolean b) -> b;
assertTrue(
Predicate.not(isTrue).test(false)
);
Lambda说:我还能再来来,你敢吗?
Lambda表达式中的参数是支持类型推断的,这次又往悬崖边挪了挪,支持了var变量,并允许@Nonnull、@Nullable等修饰符,虽然有些个限制,不得不说简洁和方便了许多,不免让人有些担心起来,老兰你可别掉下去啊!
Predicate<Boolean> isTrue = (@Nonnull var b) -> b;
assertTrue(
isTrue.test(true)
);
HttpClient:Web都要3.0,我也要雄起
HTTP都2了好些年了,WebSocket用得也很多,Web都要3.0了,Java的光棍儿子看了看手里笨重的祖传HttpURLConnection老枪,狠狠心说:都焦了,换个新的吧!
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.build();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://worldtimeapi.org/api/timezone/Europe/London")).build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
assertEquals(200, response.statusCode());
Flight recorder:看我干爹多好
都说现在是拼爹的时代,戏子的后代继续想做个星二代,作家也想让自己的子女继续在自己的圈子里混下去,就连Java也开始拼爹了,Oracle眼含热泪把自己私藏多年的飞行记录功能拿出来给了Java棍棍,棍棍感激涕零的说,看我干爹多好,以后再也不怕生病了。
Java 12
String:爱哭的孩子有奶吃
老话说的好啊,爱哭的孩子有奶吃,String在Java 12版又被翻了牌子,加了两个不痛不痒的方法,感觉Oracle有点矫枉过正、用力过猛的意思,不信你看。
.indent- 通过给定的偏移量调整每行的缩进,可以是正数或负数。
.transform— 对字符串应用trasform转换函数。
assertEquals(
" hello\n world!\n",
"hello\nworld!".indent(4)
);
assertEquals(
"Capital",
"capital".transform((str) -> str.substring(0, 1).toUpperCase() + str.substring(1))
);
File:我也会玩找不同
真是文本为王的时代啊,继String被受宠之后,Files文件处理类也添加了文本相关的方法mismatch,使用这个方法可以在两个文件之间的比较中找到第一个不匹配的字节所在的索引位置。这是在干啥呀?这届Java真的是让人看不懂啊!
Path target = Path.of("target");
Path x = Files.createTempFile(target, "x", ".txt");
Path y = Files.createTempFile(target, "y", ".txt");
Files.writeString(x,"The quick brown fox jumps over the lazy dog");
Files.writeString(y,"The fast brown fox jumps over the lazy dog");
// ^
assertEquals(
4,
Files.mismatch(x, y)
);
Collectors:谁要改水电?来找我啊!
都看过红锅在装修工地的短视频吗?是不是很搞笑?这不,Java 12里面的集合工具类也要搞装修做网红了,不知从哪里学会了做三通,嚷嚷着要揽活了,还真是魔幻哪!
var numbers = Stream.of(10, 20, 30);
var average = numbers.collect(
Collectors.teeing(
Collectors.summingInt(i -> i),
Collectors.counting(),
(sum, count) -> sum / count
)
);
assertEquals(20, average);
NumberFormat:看我的24K大金牙
曾几何时,国内也开始学老外,薪资数目都开始说多少K了,明明很不符合国内的习惯吗?这不我们顺势就升华了一下,多少万都说多少W了,估计这个老外要懵逼了,哈哈!言归正传,看一下NumberFormat推出的这个紧凑型数字格式化的方法,是不是很实用?哎!就是希望在下个版本把W也加上。
NumberFormat shortFormat = NumberFormat.getCompactNumberInstance(new Locale("en", "GB"), NumberFormat.Style.SHORT);
shortFormat.setMaximumFractionDigits(2);
assertEquals(
"12.35K",
shortFormat.format(12345)
);
Java 13
第“13”个人伤害了耶稣,老外就从此恨上了这个数字,这个版本连个毛的特性都没有。
Java 14
Switch:哥也不再是当年的哥
switch也能做表达式了,能为社会做点儿贡献了,哥已不在是当年的哥......
var month = AUGUST;
boolean isSummer = switch(month) {
case JUNE, JULY, AUGUST -> true;
default -> false;
};
assertTrue(isSummer);
NPE:色即是空,空即是色
还记得史上最昂贵的异常吗?那就是我空指针异常了,你不是一直不知道什么是空吗?这回我可以认真地告诉你了。
String missing = null;
try {
missing.toLowerCase();
} catch (NullPointerException npe) {
assertEquals("Cannot invoke \"String.toLowerCase()\" because \"missing\" is null", npe.getMessage());
}
Java 15
文本块:躺平多好,别那么拼!
Java 15终于良心发现了,多行文本再也不用那么拼了。
var atLast = """
{
"text": "blocks!"
}
""";
隐藏类:隔壁老王最爱
Java 15 引入了使用无法被其他类链接或通过反射发现的隐藏类,简直是隔壁老王日思夜想的傍身技能啊!
InputStream stream = TestJavaFifteen.class.getClassLoader().getResourceAsStream("HiddenClass.class");
MethodHandles.Lookup lookup = MethodHandles.lookup()
.defineHiddenClass(stream.readAllBytes(), true, MethodHandles.Lookup.ClassOption.NESTMATE);
Class<?> hidden = lookup.lookupClass();
Object instance = hidden.getDeclaredConstructor().newInstance();
Object result = hidden.getMethod("hello").invoke(instance);
assertEquals("Hello World!", result);
Shenandoah、ZGC:不要停!
最烦GC(我说的可是垃圾回收啊,别想歪了!)时候的停顿了,这一直是Java被诟病的地方。不过,这回再也不用担心了,Java 15一下放出了Shenandoah和ZGC两款高性能GC神器,后者的GC停顿时间甚至不超过10毫秒,简直无感啊!
Java 16
Day period:还有人傻傻分不清傍晚和晚上、早上和上午吗?
Java日期格式符号增加了B字符,用于使用本地习惯选择显示一天中的时段,如:上午/中午/下午/傍晚/晚上/午夜 等。
LocalTime date = LocalTime.parse("07:13:09");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h B");
assertEquals(
"7 in the morning",
date.format(formatter)
);
Stream toList:以后要走正门啊!
Stream API在Java 石榴版推出了姗姗来迟的toList,让我们整整等了8个版本,这是搞饥饿营销的地方吗?Oracle大哥,你的良心不会痛吗?
//Java 16
var list = Stream.of(1, 2, 3).toList();
assertEquals(
List.of(1, 2, 3),
list
);
//java 8
Stream.of(1, 2, 3).collect(Collectors.toList());
Record:海枯石烂永不变
Java 石榴版开始和钻石抢市场了,推出了用Record创建不可变对象的方法,以后码农是不是连买钻石的钱都省了?
public record Movie(String title, Integer rating) {}
@Test
void records() {
var starWars = new Movie("Star Wars", 5);
assertEquals(
"Star Wars", starWars.title()
);
assertEquals(
5, starWars.rating()
);
assertEquals(
starWars,
new Movie("Star Wars", 5)
);
}
instanceof:接拐!
Java石榴版的instanceof看好了自己的腿病,再也不用拄拐(括号)了!
Object b = true;
if (b instanceof Boolean c) {
// c is Boolean type
}
Object value = data.get("key");
if (value instanceof String s) {
System.out.println(s.substring(1));//e
}
Local enums、interface:这是俺媳妇儿,谁也别惦记!
Java石榴版引入了本地枚举和本地接口特性,作用域限于方法内部,都教人开始吃独食了!
//本地枚举
@Test
void localEnums() {
enum TriBoolean {
True,
False,
Maybe
}
assertEquals(
TriBoolean.True,
TriBoolean.True
);
}
//本地接口
@Test
void interfaces() {
interface Hello {
String hello();
String goodbye();
}
Hello hello = new Hello() {
@Override
public String hello() {
return "hello world!";
}
@Override
public String goodbye() {
return "goodbye cruel world!";
}
};
assertEquals(
"hello world!",
hello.hello()
);
assertEquals(
"goodbye cruel world!",
hello.goodbye()
);
}
Java 17
Sealed classes/intefaces:小女子只卖艺不卖身
老十七版的Java推出了密封类和密封接口,限制了可以扩展或实现它们的类集,增强了类型安全性,也同switch语句一起为模式匹配出一份力。
sealed interface CatFamily permits Lion, Tiger {
String miow();
}
final class Lion implements CatFamily {
@Override
public String miow() {
return "ROAR!";
}
}
final class Tiger implements CatFamily {
@Override
public String miow() {
return "CHOMP!";
}
}
// compilation error, because Bear is not permitted by the interface permissions on line 1
final class Bear implements CatFamily {
@Override
public String miow() {
return "Uhh?";
}
}
完结
Java 18 不是LTS,也没有添加新的语言特性,后续的LTS也可能由3年一版加速为2年一版了,Oracle这是急了啊,对此你怎么看呢?