java11学习
阅读数:62 评论数:0
跳转到新版页面分类
python/Java
正文
一、概述
java11之前的一个LTS版本是Java8,从版本11开始,Oracle JDK只能由开发人员免费使用,公司需要与Oracle签订有偿支持合同。
二、新特性
1、lambda参数的局部变量语法
即:允许在隐式类型lambda表达式的参数中使用“var”。
以一个例子来说明:
(1)一个显示类型的lambda表达式,显示表示指定了参数l和s的数据类型
(List<String> l, String s) -> l.add(s);
(2)编译器可以从上下文推出参数类型,所以可以转为隐式表达式
(l, s) -> l.add(s);
(3)但有时,有些注解需要放在参数的类型上,而不能直接放在名称上,所以有了var的需要。
(@Nonnull List<String> l, @Nullable String s) -> l.add(s);
//就可以改写成
(@Nonnull var l, @Nullable var s) -> l.add(s);
这三种风格:为所有变量指定类型、省略所有类型、对所有变量使用var,不能混用,最终选择开发者自己选择。
2、http客户端
包括新的HttpClient类,简化了HTTP的使用。
3、新的Collection.toArray()方法
在Java 11之前,Collection接口提供了两个toArray()方法将集合转换为数组。
List<String> list = List.of("foo", "bar", "baz");
Object[] strings1 = list.toArray();
String[] strings2a = list.toArray(new String[list.size()]);
String[] strings2b = list.toArray(new String[0]);
第一个toArray()方法(不带参数)返回一个Object数组。
第二个toArray()方法需要一个请求类型的数组,如果此数组至少与集合一样大,则元素将存储在此数组中(strings2a),否则将创建所需大小的新数组(strings2b)。
从java 11开始,我们还可以这样写:
String[] strings = list.toArray(String[]::new);
4、为String类添加了一些新方法
isBlank、lines、strip、stripLeading、stripTrailing、repeat。
5、新的文件方法
通过使用Files类中的新的readString和writeString静态方法可以更容易的从文件中读取和写入字符串。
Path filePath = Files.writeString(Files.createTempFile(tempDir, "demo", ".txt"), "Sample text");
String fileContent = Files.readString(filePath);
assertThat(fileContent).isEqualTo("Sample text");
6、Path.of()
之前,我们必须通过Paths.get()或File.toPath()创建Path对象,java 11开始,可以使用Path.of()。
// Relative path foo/bar/baz
Path.of("foo/bar/baz");
Path.of("foo", "bar/baz");
Path.of("foo", "bar", "baz");
// Absolute path /foo/bar/baz
Path.of("/foo/bar/baz");
Path.of("/foo", "bar", "baz");
Path.of("/", "foo", "bar", "baz");
7、一个新的垃圾回收器:Epsilon GC
-XX:+UseEpsilonGC
此GC只进行内存分配,不进行内存回收。
8、启动单文件源代码程序
假设有一个名为Hello.java
public class Hello {
public static void main(String[] args) {
if (args.length > 0) {
System.out.printf("Hello %s!%n", args[0]);
} else {
System.out.println("Hello!");
}
}
}
在java 11之前,运行它
$ javac Hello.java
$ java Hello Bob
Hello Bob!
从java 11之后,可以
$ java Hello.java Bob
Hello Bob!
在Linux和macOS上,我们可以直接编写可执行的java脚本 (不要使用.java扩展名)。
#!/usr/bin/java --source 11
public class Hello {
public static void main(String[] args) {
if (args.length > 0) {
System.out.printf("Hello %s!%n", args[0]);
} else {
System.out.println("Hello!");
}
}
}
9、引入嵌套的概念和访问规则
示例代码:
(1)假设有一段代码
public class Outer {
private void outerPrivate() {
}
class Inner {
public void innerPublic() {
outerPrivate(); // access Outer's private method!
}
}
}
我们在编译上面的源码时,会生成两个类:Outer和Outer$Inner。
(2)内部类可以访问外部类的私有属性,破坏了jvm访问规则
JVM访问规则不允许一个类访问另一个类的私有属性,但是却允许内部类访问外部的的私有属性。
这是Java编译器创建了一个桥接文件 access$000,生成了类似如下的代码:
public class Outer {
private void outerPrivate() {
}
void access$000(){
outerPrivate();
}
}
class Inner {
final Outer obj;
public void innerPublic() {
obj.access$000(); // access Outer's private method!
}
}
(3)使用反射时会出现的问题
public void innerPublicReflection(Outer ob) throws Exception {
Method method = ob.getClass().getDeclaredMethod("outerPrivate");
method.invoke(ob);
}
当我们尝试从Inner类反射地调用outerPrivate是不允许的。
java.lang.IllegalAccessException:
class Outer$Inner cannot access a member of class Outer with modifiers "private"
java11中,在类文件中包含了两个属性:
NestMembers | 标识其包含的静态已知的嵌套成员 |
NestHost | 标识其嵌套宿主 |
现在编译器不再生成桥接访问,反射的使用也正常。