一 前述
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 introjshell> System.out.print("halo java")halo javajshell>
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为变量名
@Testpublic void test1(){int var =10;System.out.println(var);}
1)在lambda表达式中使用
@Testpublic 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()
@Testpublic void test1() {List<Integer> list = List.of(1, 2, 3, 4, 5);// list.add(6); 不允许新增元素,会报异常 java.lang.UnsupportedOperationExceptionSystem.out.println(list);}
1)Arrays.asList()方法也可以创建集合对象
@Testpublic 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方法中有相同元素时,会提示异常
@Testpublic void test3() {Set<Integer> set = Set.of(1, 2, 3, 41, 1);System.out.println(set);// java.lang.IllegalArgumentException: duplicate element: 1}
3)当添加新元素时,不允许
@Testpublic void test3() {Set<Integer> set = Set.of(1, 2, 3, 41);// set.add(55); java.lang.UnsupportedOperationExceptionSystem.out.println(set);}
五 Stream新增的API
流的基本操作步骤
1)创建流
2)中间操作
3)终止操作
Stream是Java8的新特性,Java9开始对Stream增加了4个新方法
5.1 增加单个参数构造器,可以null
1)Stream.of(null) 会提示空指针异常
@Testpublic 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 splitreturn StreamSupport.stream(new WhileOps.UnorderedWhileSpliterator.OfRef.Taking<>(spliterator(), true, predicate),isParallel()).onClose(this::close);}
// 示例代码@Testpublic 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 splitreturn StreamSupport.stream(new WhileOps.UnorderedWhileSpliterator.OfRef.Dropping<>(spliterator(), true, predicate),isParallel()).onClose(this::close);}
// 示例代码@Testpublic 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重载
流的迭代,用于产生流,创建流
@Testpublic 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():判断是否为空白字符
@Testpublic 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键,和换行符。
@Testpublic void test(){String str = " \n \r \t abc \n";String str1 = str.strip();System.out.println(str1); // abcSystem.out.println(str1.length()); // 3}
3)stripLeading():去除字符串头部的空白字符
@Testpublic void test2(){String str = " \n \r \t abc \n ";String str1 = str.stripLeading();System.out.println(str1); // abcSystem.out.println(str1.length()); // 7}
4)stripTrailing():去除字符串尾部的空白字符
@Testpublic void test3(){String str = " \n \r \t abc \n ";String str1 = str.stripTrailing();System.out.println(str1); // abcSystem.out.println(str1.length()); // 12}
5)repeat(n):复制字符串,参数表示复制次数
@Testpublic void test4() {String str = "Java";String repeat = str.repeat(3);System.out.println(repeat); // JavaJavaJava}
6)lines():将字符串按照分隔符进行分割,然后返回一个流Stream
@Testpublic void test5() {String str = "Java\nhalo";Stream<String> lines = str.lines(); // 实际上以换行符进行分割,返回一个流System.out.println("字符串行数:" + lines.count()); // 2}
6.2 Optional类新增的API
1)ofNullable()
@Testpublic 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 同步请求
@Testpublic 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 异步请求
@Testpublic 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 停顿时间不会随着堆的增长和存货对象的增长而变长。
