一 前述
1)jshell 2)局部变量的类型推断 3)新增的API
1.1 Java11是一个长期支持的版本(LTS)
1)对于企业来说,选择Java11将意味着长期的,可靠的,可预测的技术路线。其中免费的 openJDK11 确定将得到openJDK社区的长期支持,LTS是可以放心选择的版本。
2)从JVM GC的角度来看,JDK11 引入了两种新的GC,其中包括了也许是划时代的意义的ZGC,虽然其目前还是实验特性,但是从能力上看,这是JDK的一个巨大的突破,为特定生产环境的苛刻需求提供了一个可能的选择。
二 JShell
2.1 JShell概述
1)JShell类似于Python的shell工具
2)JShell是个交互性工具,可以让Java像脚本语言一样运行,可以从控制台上启动jshell,在jshell中直接输入表达式并查看结果
3)适用于测试一个方法或者是对表达式求值时
C:\Program Files\Java\jdk11.0.8_10\bin>jshell
| 欢迎使用 JShell -- 版本 11.0.8
| 要大致了解该版本, 请键入: /help intro
jshell> System.out.print("halo java")
halo java
jshell>
2.2 创建类和方法
1)Jshell类似于Java的main方法,但是也可以创建类和方法
2)不需要再解析main方法,直接执行语句时,就相当于在main方法中运行了
三 局部变量类型判断
3.1 创建maven项目
<build>
<plugins>
<!-- 设置maven项目的jdk编译版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.11</source>
<target>1.11</target>
</configuration>
</plugin>
</plugins>
</build>
3.2 var 局部变量类型推断
1)var a = 10; 这个表达式可以由10推断出a的类型为int 2)但是 var a; 这样不赋值的表达式不可以,因为无法推断出a的类型是什么 3)在类声明属性的时候,不可以使用var 4)var不是一个关键字,int var = 10; 这样是可以运行的,var为变量名
@Test
public void test1(){
int var =10;
System.out.println(var);
}
1)在lambda表达式中使用
@Test
public void test2() {
Consumer consumer = (@Deprecated var x) -> { // var 可以推断出 x 的类型
System.out.println(x);
};
consumer.accept(10);
}
2)在lambda表达式上使用var还是和原来一样,有什么作用呢?
- 一般使用lambda表达式,如果不知道类型,那么就无法在参数上使用注解,加上了var之后,可以使用注解来修饰参数
四 集合新增的API
4.1 List.of()
@Test
public void test1() {
List<Integer> list = List.of(1, 2, 3, 4, 5);
// list.add(6); 不允许新增元素,会报异常 java.lang.UnsupportedOperationException
System.out.println(list);
}
1)Arrays.asList()方法也可以创建集合对象
@Test
public void test2() {
String[] arr = {"a", "bb", "cccc"};
List<String> strings = Arrays.asList(arr);
//strings.add("dd"); 也不允许添加元素
System.out.println(strings);
}
2)上面两者返回的集合对象不同,Arrays返回的是自己内部类的ArrayList类对象,List.of() 方法返回的是 ImmutableCollections.ListN<> 类对象,这是List接口中的一个static final内部类,不允许添加新的元素。
4.1 Set.of()
1)和List一样,返回一个Set对象
2)of方法中有相同元素时,会提示异常
@Test
public void test3() {
Set<Integer> set = Set.of(1, 2, 3, 41, 1);
System.out.println(set);
// java.lang.IllegalArgumentException: duplicate element: 1
}
3)当添加新元素时,不允许
@Test
public void test3() {
Set<Integer> set = Set.of(1, 2, 3, 41);
// set.add(55); java.lang.UnsupportedOperationException
System.out.println(set);
}
五 Stream新增的API
流的基本操作步骤
1)创建流
2)中间操作
3)终止操作
Stream是Java8的新特性,Java9开始对Stream增加了4个新方法
5.1 增加单个参数构造器,可以null
1)Stream.of(null) 会提示空指针异常
@Test
public void test2(){
Stream<Object> stream = Stream.of(null);
/**
* 1 先调用这个方法,参数为数组对象
* public static<T> Stream<T> of(T... values) {
* return Arrays.stream(values);
* }
* 2 Stream()构造器的第三个参数为数组长度,null.length则直接提示空指针异常
* ---> public static <T> Stream<T> stream(T[] array) {
* return stream(array, 0, array.length);
* }
*/
}
2)Stream.ofNullable(null):完美解决这个问题
5.2 takeWhile()、dropWhile()
1)takeWhile:从流中一直获取判定器为真的元素,一旦遇到元素为假,就终止处理,丢弃后面的元素
// JDK11源码
default Stream<T> takeWhile(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
// Reuses the unordered spliterator, which, when encounter is present,
// is safe to use as long as it configured not to split
return StreamSupport.stream(
new WhileOps.UnorderedWhileSpliterator.OfRef.Taking<>(spliterator(), true, predicate),
isParallel()).onClose(this::close);
}
// 示例代码
@Test
public void test3() {
Stream<Integer> stream = Stream.of(5, 2, 4, 5, 5, 1);
Stream<Integer> stream1 = stream.takeWhile((x) -> {
if (x > 2) {
return true;
} else {
return false;
}
});
stream1.forEach(System.out::println); // 5
}
2)dropWhile:从流中开始丢弃判定器为真的元素,一旦遇到假的,则返回后面的所有元素
// JDK11源码
default Stream<T> dropWhile(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
// Reuses the unordered spliterator, which, when encounter is present,
// is safe to use as long as it configured not to split
return StreamSupport.stream(
new WhileOps.UnorderedWhileSpliterator.OfRef.Dropping<>(spliterator(), true, predicate),
isParallel()).onClose(this::close);
}
// 示例代码
@Test
public void test() {
Stream<Integer> stream = Stream.of(5, 2, 4, 5, 5, 1);
stream.dropWhile(x -> {
if (x > 2) {
return true;
}
return false;
}).forEach(System.out::println); // 2,4,5,5,1
}
5.3 iterate重载
流的迭代,用于产生流,创建流
@Test
public void test4() {
// 第一个参数是种子,第二个参数是单位运算符,对前一个元素进行操作生产下一个元素
Stream<Integer> iterate = Stream.iterate(1, t -> t * 2 + 1);
iterate.limit(10).forEach(System.out::println);
System.out.println("============================");
// 第二个参数是判定器,限制流的无限扩展
// 这个iterate重载的方法是jak11新增
Stream<Integer> stream = Stream.iterate(1, t -> t < 1000, t -> t * 2 + 1);
stream.forEach(System.out::println);
}
六 字符串和Optional
字符串新增的API主要是对空白字符的处理 1)isBlank() 2)strip() 3)stripLeading() 4)stripTrailing() 5)repeat() 6)lines()
6.1 String类新增的API
1)isBlank():判断是否为空白字符
@Test
public void test1() {
// 1、str中包含了英文,中文的空格
String str = " \n \r \t \n";
boolean blank = str.isBlank();
System.out.println(blank); // true
}
2)strip():去除字符串的首尾的空白字符,包括英文和其他所有语言的空白字符
2.1)trim():同样去除字符串的首尾的空白字符,但是只去除码字小于等于32的空白字符,不能去除中文的空格,只能去除空格,tab键,和换行符。
@Test
public void test(){
String str = " \n \r \t abc \n";
String str1 = str.strip();
System.out.println(str1); // abc
System.out.println(str1.length()); // 3
}
3)stripLeading():去除字符串头部的空白字符
@Test
public void test2(){
String str = " \n \r \t abc \n ";
String str1 = str.stripLeading();
System.out.println(str1); // abc
System.out.println(str1.length()); // 7
}
4)stripTrailing():去除字符串尾部的空白字符
@Test
public void test3(){
String str = " \n \r \t abc \n ";
String str1 = str.stripTrailing();
System.out.println(str1); // abc
System.out.println(str1.length()); // 12
}
5)repeat(n):复制字符串,参数表示复制次数
@Test
public void test4() {
String str = "Java";
String repeat = str.repeat(3);
System.out.println(repeat); // JavaJavaJava
}
6)lines():将字符串按照分隔符进行分割,然后返回一个流Stream
@Test
public void test5() {
String str = "Java\nhalo";
Stream<String> lines = str.lines(); // 实际上以换行符进行分割,返回一个流
System.out.println("字符串行数:" + lines.count()); // 2
}
6.2 Optional类新增的API
1)ofNullable()
@Test
public void test1(){
// of(null):会抛出异常,不安全
// Optional<Object> optional = Optional.of(null);
// ofNullable():可以兼容空指针,但是实际传入null,也要注意小心
Optional<Object> optional1 = Optional.ofNullable(null);
Object op = optional1.orElse("null"); // 如果为空则返回参数的值
System.out.println(op);
}
七 HttpClient
Java9开始引入的一个处理 HTTP 请求的 HTTP Client API,该API 支持同步异步 在Java11中成为正式可以状态,可以在 java.net 包下找到这个API
7.1 同步请求
@Test
public void test() throws Exception {
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://www.baidu.com/")).build();
HttpResponse.BodyHandler<String> bodyHandler = HttpResponse.BodyHandlers.ofString();
// send():同步方法
HttpResponse<String> response = httpClient.send(request, bodyHandler);
System.out.println(response.body());
}
7.2 异步请求
@Test
public void test1() throws ExecutionException, InterruptedException {
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://www.baidu.com/")).build();
HttpResponse.BodyHandler<String> bodyHandler = HttpResponse.BodyHandlers.ofString();
// sendAsync():异步方法
CompletableFuture<HttpResponse<String>> sendAsync = httpClient.sendAsync(request, bodyHandler);
HttpResponse<String> response = sendAsync.get();
String body = response.body();
System.out.println(body);
}
八 EpsilonGC和ZGC
8.1 新的Epsilon垃圾收集器
1)jdk对这个新特性的描述:开发一个处理新的内存分配,但是不实现任何实际垃圾内存回收机制的GC,一旦可用堆内存用完,JVM就会退出
2)如果有 System.gc() 调用,实际上也什么都不会发生,这个场景下和 -XX:+DisableExplicitGC 效果一样,因为没有内存回收,这个实现可能会警告用户强制GC是徒劳的
3)使用EpsilonGC 的原因:
- 提供完全被动的GC 实现,具有有限的分配限制,和尽可能低的延迟开销,但是代价是内存占用和内存吞吐量
- 众所周知,Java实现可广泛选择高度可配置的GC 实现,各种可用的收集器最终满足不同的需求,即使它们的可配置性使得它们的功能相交,有时候更容易维护单独的实现,而不是在现有的GC 实现上堆积另一个配置选项
4)主要用途:
- 性能测试(可以帮助过滤掉GC引起的性能假象)
- 内存压力测试(例如,知道测试用例应该不分配超过1GB的内存,我们就可以使用-Xmx1g -XX:+UseEpsilonGC,如果程序有问题,则程序崩溃)
- 非常短的JOB任务(对象这种任务,接受GC清理堆那都是浪费空间)
- VM接口测试
- Last-drop 延迟&吞吐改进
8.2 ZGC
ZGC,A Scalable Low-Latency Garbage Collector(Experimental) ZGC应该是JDK11最为瞩目的特性,没有之一,但是它还是实验性的产品,还不建议使用到生产环境上面
1)GC暂停时间不会超过10ms;既能处理几百兆的小堆,也能处理几个T的大堆(OMG);和G1 相比,应用吞吐能力不会下降超过15%;为未来的GC功能和利用colord指针以及Load barriers 优化奠定基础;初始只支持 64 位系统。
2)ZGC的设计目标:支持TB级的内存容量,暂停时间低(<10ms),对整个程序的吞吐量影响小于15%。将来该可以扩展实现机制,以支持不少令人兴奋的功能,例如多层堆(即热对象置于DRAM和冷对象置于NVMe内存),或者压缩堆。
3)GC是Java的主要优势之一,然而,当GC停顿太长时间,就会开始影响应用的响应时间,消除或者减少GC停顿时长,Java将对更广泛的应用场景是一个更有吸引力的平台,此外,现代的系统可用内存在不断的增长,用户和程序员吸引JVM能够以高效的方式充分利用这些内存,并且无需长时间的GC暂停时间。
4)ZGC是一个并发,基于region,压缩型的垃圾收集器,只有 root 扫描阶段会 STW,因此GC 停顿时间不会随着堆的增长和存货对象的增长而变长。