java 11 新特性源码分析和使用
Java 11 的一些重要功能包括:
- 使用单个命令运行 Java 文件
- String 类中的新实用程序方法
- Lambda 参数的局部变量语法
- 基于嵌套的访问控制
- JEP 321:HTTP 客户端
- 在文件中读取/写入字符串
- JEP 328:飞行记录器
Java 字符串方法
isBlank() –此实例方法返回一个布尔值。空字符串和仅包含空格的字符串将被视为空白。
public static void isBlank(){
String out = "";
String out1 = null;
System.out.println(out.isBlank());
System.out.println(out.isEmpty());
//这里会抛出空指针异常
System.out.println(out1.isBlank());
System.out.println(out1.isEmpty());
}
isBlank()和 isEmpty()之间的区别:
public boolean isBlank() {
return indexOfNonWhitespace() == length();
}
private int indexOfNonWhitespace() {
if (isLatin1()) {
return StringLatin1.indexOfNonWhitespace(value);
} else {
return StringUTF16.indexOfNonWhitespace(value);
}
}
isBlank()使用了两个方法来确定 String 是否为空字符串
但是首先我们要关注的 String 的声明方式
String(byte[] value, byte coder) {
this.value = value;
this.coder = coder;
}
每个 String 的构造函数是不必要的,因为字符串不可变,但是这里需要声明一个代表空字符的序列
再来看 isLation1()
static final boolean COMPACT_STRINGS;
static {
COMPACT_STRINGS = true;
}
@Native static final byte LATIN1 = 0;
private boolean isLatin1() {
return COMPACT_STRINGS && coder == LATIN1;
}
静态声明 COMPACT_STRINGS,但是 COMPACT_STRINGS 实在 jvm 启动时才被赋值,这样可能可以避免循环依赖
我对于这里的理解是当字符串被经禁止时,编码始终为 UTF16,但是为了 JIT 的效率,优化写法,所以此处 COMPACT_STRINGS 这样声明.
isLatin1()是为了判断编码格式为拉丁还是 UTF16
StringLatin1.indexOfNonWhitespace(value)
StringUTF16.indexOfNonWhitespace(value)
不管字符串的编码格式为什么,他们最终和 length()对比
public int length() {
return value.length >> coder();
}
byte coder() {
return COMPACT_STRINGS ? coder : UTF16;
}
字符串中的代码单位始终采用的是 UTF16
简单来说 isBlank()是一个判断字符串编码(LATIN1 和 UTF16)后获得 byte 长度,它们的对比对象都是 UTF16 的 byte 长度
相对来说 isEmpty()要简单得多
isEmpty()
private final byte[] value;
public boolean isEmpty() {
return value.length == 0;
}
它仅仅是建立了一个 byte[]用于字符存储,在它的源码上有一句话,’ because value is never null’因为
public String() {
this.value = "".value;
this.coder = "".coder;
}
但是,为什么我们在声明一个 String 为 null,会抛出空指针异常呢?我认为这个异常应该是没有找到这个字符串,而不是 String 类里面抛出的,我做了一个尝试,运行以下代码
把断点打在 isBlank()
这是报文
断点并没有进入到 isBlank(),证明 String 为 null,本身就无法调用到 String 中的方法
lines()返回从该字符串中提取的行流
public static void lines() {
String out = " \n n \r r \r\n rn ";
System.out.println(out.lines().collect(Collectors.toList()));
}
控制台输出
[ , n , r , , rn ]
此方法只能针对于换行符’\n’ , ‘\r’
它比 split(’\R’)更快地搜索新的行终止符
strip() 简单来说就是返回去掉空格的字符串
它和 trim()有什么不一定样呢,我们首先来看下代码输出
public static void strip(){
String str = " JD ";
System.out.print("Start");
System.out.print(str.strip());
System.out.println("End");
System.out.print("Start");
System.out.print(str.stripLeading());
System.out.println("End");
System.out.print("Start");
System.out.print(str.stripTrailing());
System.out.println("End");
}
StartJDEnd
StartJD End
Start JDEnd
最大的不一样 strip()可以选择去掉空格符分隔的数组头还是尾,
public String strip() {
String ret = isLatin1() ? StringLatin1.strip(value)
: StringUTF16.strip(value);
return ret == null ? this : ret;
}
同样的,java11 中对于字符串的操作几乎都判断了字符串的编码格式是 LATIN1 还是 UTF16
repeat()返回其值重复的字符串的串联字符串
通俗来说就是返回一个重复几次的字符串
public static void repeat(){
System.out.println("12".repeat(2));
}
1212
当然这个会有最大重复限制,不过也和字符串的长度相关,可以在源码中找到
@Native public static final int MAX_VALUE = 0x7fffffff;
public String repeat(int count) {
if (count < 0) {
throw new IllegalArgumentException("count is negative: " + count);
}
if (count == 1) {
return this;
}
final int len = value.length;
if (len == 0 || count == 0) {
return "";
}
if (len == 1) {
final byte[] single = new byte[count];
Arrays.fill(single, value[0]);
return new String(single, coder);
}
if (Integer.MAX_VALUE / count < len) {
throw new OutOfMemoryError("Repeating " + len + " bytes String " + count +
" times will produce a String exceeding maximum size.");
}
final int limit = len * count;
final byte[] multiple = new byte[limit];
System.arraycopy(value, 0, multiple, 0, len);
int copied = len;
for (; copied < limit - copied; copied <<= 1) {
System.arraycopy(multiple, 0, multiple, copied, copied);
}
System.arraycopy(multiple, 0, multiple, copied, limit - copied);
return new String(multiple, coder);
}
MAX_VALUE为2的31次方-1
Lambda参数的局部变量语法
用于声明隐式类型的lambda表达式的形式参数
public static void lambda() {
var list = new ArrayList<String>();
//java11
list.stream()
.map((var s) -> s.toLowerCase())
.collect(Collectors.toList());
//java8
list.stream()
.map(String::toLowerCase)
.collect(Collectors.toList());
}
file读写
java从8开始就一直在简化文件的读写,对于开发者来说未尝不是一件好事.
public static void file() throws IOException {
Path path = Files.write(Files.createTempFile("test", ".txt"), Collections.singleton("公众号:java企业级应用"));
System.out.println(path);
String s = Files.readString(path);
System.out.println(s); //This was posted on J
}