reference
[1] http://www.cnblogs.com/IcanFixIt/p/7278696.html
List, Set and Map
在Java语言中支持collection literals是非常需要的功能。 JDK 9替代了对collection literals的支持,更新了Collection API,而是在List
,Set
和Map
接口中添加了of()
静态工厂方法,分别返回一个不可变的List
,Set
和Map
。该方法被重载,指定集合的零到十个元素。 List
和Set
接口提供了可变参数的of()
方法,用于创建一个包含任意数量的元素的List
和Set
。 Map
接口提供了ofEntries()
静态工厂方法,用于创建一个不可变的任意数量条目的Map
。 Map
接口还包含一个静态的entry()
方法,它接受一个键和一个值作为参数并返回一个Map.Entry
实例。 ofEntries()
和entry()
方法一起使用来创建任意数量条目的不可变的Map
。
这些接口中的新的静态工厂方法为性能做了调整。 List.of()
和Set.of()
方法不允许使用null元素。 Set.of()
方法不允许重复的元素。 Map.of()
和Map.ofEntries()
方法不允许重复键,或者将null作为键或值。
HTTP/2 Client API
JDK 9添加了一个HTTP/2 Client API,可以在Java应用程序中使用HTTP请求和响应。 API提供类和接口来开发具有身份验证和TLS的WebSocket客户端。 API位于jdk.incubator.http包中,该包位于jdk.incubator.httpclient模块中。
三个抽象类,HttpClient
,HttpRequest
和HttpResponse
,WebSocket
接口是HTTP/2 Client API的核心。这些类型的实例使用构建器创建。 HttpClient
类是不可变的。HttpClient
类的实例保存可以重复用于多个HTTP请求的HTTP连接配置。 HttpRequest
类实例表示HTTP请求。 HttpResponse
类的实例表示从服务器接收的HTTP响应。可以同步或异步地发送和接收HTTP请求和响应。
WebSocket
接口的实例表示一个WebSocket
客户端endpoint。与WebSocket服务器端endpoint的通信是异步完成的。 WebSocket API是基于事件的。需要为WebSocket客户端endpoint指定一个监听器,它是WebSocket.Listener
接口的一个实例。监听器通过调用其适当的方法 —— 当事件发生在endpoint上时,例如,当通过调用监听器的onOpen()
方法成功完成与对等体的打开握手时,通知监听器。 API支持与对等体交换文本以及二进制消息。消息可以部分交换。
栈遍历
在JDK 9之前,Stack-Walking API存在以下缺点:
- 效率不高。
Throwable
类的getStrackTrace()
方法返回整个栈的快照。 没有办法在栈中只得到几个顶部栈帧。 - 栈帧包含方法名称和类名称,而不是类引用。 类引用是
Class<?>
类的实例,而类名只是字符串。 - JVM规范允许虚拟机实现在栈中省略一些栈帧来提升性能。 因此,如果有兴趣检查整个栈,那么如果虚拟机隐藏了一些栈帧,则无法执行此操作。
- JDK和其他类库中的许多API都是调用者敏感(caller-sensitive)的。 他们的行为基于调用者的类而有所不同。 例如,如果要调用
Module
类的addExports()
方法,调用者的类必须在同一个模块中。 否则,将抛出一个IllegalCallerException
异常。 在现有的API中,没有简单而有效的方式来获取调用者的类引用。 这样的API依赖于使用JDK内部API ——sun.reflect.Reflection
类的getCallerClass()
静态方法。 - 没有简单的方法来过滤特定实现类的栈帧。
JDK 9引入了一个新的Stack-Walking API,它由java.lang包中的StackWalker
类组成。 该类提供简单而有效的栈遍历。 它为当前线程提供了一个顺序的栈帧流。 从栈生成的最上面的到最下面的栈帧,栈帧按顺序记录。 StackWalker
类非常高效,因为它可以懒加载的方式地评估栈帧。 它还包含一个便捷的方法来获取调用者类的引用。 StackWalker
类由以下成员组成:
StackWalker.Option
嵌套枚举StackWalker.StackFrame
嵌套接口- 获取
StackWalker
类实例的方法 - 处理栈帧的方法
- 获取调用者类的方法
在JDK 9之前,StackTraceElement
类的实例被用来表示栈帧。 JDK 9中的Stack-Walker API使用StackWalker.StackFrame
接口的实例来表示栈帧。
Tips
StackWalker.StackFrame
接口没有具体的实现类,可以直接使用。 JDK中的Stack-Walking API在检索栈帧时为你提供了接口的实例。
以下代码片段使用walk()
方法遍历整个栈,打印每个栈帧的详细信息。 这段代码与前面的代码片段使用forEach()
方法相同。
// Prints the details of all stack frames of the current thread
StackWalker.getInstance()
.walk(s -> {
s.forEach(System.out::println);
return null;
});
Tips
StackWalke
r的forEach()
方法用于一次处理一个栈帧,而walk()
方法用于处理将整个栈为帧流。 可以使用walk()
方法来模拟forEach()
方法的功能,但反之亦然
在JDK 9之前,开发人员依靠以下方法来获取调用者的调用:
SecurityManager
类的getClassContext()
方法,由于该方法受到保护,因此需要进行子类化。sun.reflect.Reflection
类的getCallerClass()
方法,它是一个JDK内部类。
JDK 9通过在StackWalker
类中添加一个getCallerClass()
的方法,使得获取调用者类引用变得容易。 方法的返回类型是Class<?>
。 如果StackWalker
未配置RETAIN_CLASS_REFERENCE
选项,则调用此方法将抛出UnsupportedOperationException
异常。 如果栈中没有调用者栈帧,则调用此方法会引发IllegalStateException
,例如,运行main()
方法调用此方法的类。
那么,哪个类是调用类? 在Java中,方法和构造函数可调用。 以下讨论使用方法,但是它也适用于构造函数。 假设在S的方法中调用getCallerClass()
方法,该方法从T的方法调用。另外假设T的方法在名为C的类中。在这种情况下,C类是调用者类。
Tips
StackWalker
类的getCallerClass()
方法在查找调用者类时会过滤所有隐藏和反射栈帧,而不管用于获取StackWalker
实例的选项如何。
流 Stream
流是由生产者生产并由一个或多个消费者消费的元素(item)的序列。 这种生产者——消费者模型也被称为source/sink模型或发布者——订阅者(publisher-subscriber )模型。 在本章中,将其称为发布者订阅者模型。
Reactive Stream 响应式流从2013年开始,作为提供非阻塞背压的异步流处理标准的倡议。 它旨在解决处理元素流的问题——如何将元素流从发布者传递到订阅者,而不需要发布者阻塞,或订阅者有无限制的缓冲区或丢弃.
Java API 的响应式流只包含四个接口:
Publisher<T>
Subscriber<T> Subscription Processor<T,R>
发布者(publisher)是潜在无限数量的有序元素的生产者。 它根据收到的要求向当前订阅者发布(或发送)元素。
订阅者(subscriber)从发布者那里订阅并接收元素。 发布者向订阅者发送订阅令牌(subscription token)。 使用订阅令牌,订阅者从发布者哪里请求多个元素。 当元素准备就绪时,发布者向订阅者发送多个或更少的元素。 订阅者可以请求更多的元素。 发布者可能有多个来自订阅者的元素待处理请求。
订阅(subscription)表示订阅者订阅的一个发布者的令牌。 当订阅请求成功时,发布者将其传递给订阅者。 订阅者使用订阅令牌与发布者进行交互,例如请求更多的元素或取消订阅。
处理者(processor)充当订阅者和发布者的处理阶段。 Processor
接口继承了Publisher
和Subscriber
接口。 它用于转换发布者——订阅者管道中的元素。 Processor<T,R>
订阅类型T的数据元素,接收并转换为类型R的数据,并发布变换后的数据。 下图显示了处理者在发布者——订阅和管道中作为转换器的作用。 可以拥有多个处理者。
JDK 9在java.util.concurrent包中提供了一个与响应式流兼容的API,它在java.base模块中。 API由两个类组成:
Flow
SubmissionPublisher<T>
Flow
类是final的。 它封装了响应式流Java API和静态方法。 由响应式流Java API指定的四个接口作为嵌套静态接口包含在Flow
类中:
Flow.Processor<T,R>
Flow.Publisher<T> Flow.Subscriber<T> Flow.Subscription
这四个接口包含与上面代码所示的相同的方法。 Flow
类包含defaultBufferSize()
静态方法,它返回发布者和订阅者使用的缓冲区的默认大小。 目前,它返回256。
SubmissionPublisher<T>
类是Flow.Publisher<T>
接口的实现类。 该类实现了AutoCloseable
接口,因此可以使用try-with-resources块来管理其实例。 JDK 9不提供Flow.Subscriber<T>
接口的实现类; 需要自己实现。 但是,SubmissionPublisher<T>
类包含可用于处理此发布者发布的所有元素的consume(Consumer<? super T> consumer)
方法。
Stream new API
JDK 9向Streams API添加了一些便利的方法,使流处理更容易,并使用收集器编写复杂的查询。
Stream
接口有四种新方法:dropWhile()
),takeWhile()
,ofNullable()
和iterate()
。对于有序流,dropWhile()
方法返回流的元素,从指定predicate
为true的起始处丢弃元素。对于无序流,dropWhile()
方法的行为是非确定性的。它可以选择删除匹配predicate
的任何元素子集。当前的实现从匹配元素开始丢弃匹配元素,直到找到不匹配的元素。 takeWhile()
方法的工作方式与dropWhile()
方法相同,只不过它从流的起始处返回匹配的元素,而丢弃其余的。如果元素为非空,则Nullable(T t)
方法返回包含指定元素的单个元素的流。如果指定的元素为空,则返回一个空的流。新的iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
方法允许使用初始种子值创建顺序(可能是无限)流,并迭代应用指定的下一个方法。当指定的hasNext
的predicate
返回false时,迭代停止。
Collectors
类在JDK 9中有两种新方法:filtering()
和flatMapping()
。 filtering()
方法返回在收集元素之前应用过滤器的收集器。如果指定的predicate
对于元素返回true,则会收集元素;否则,元素未被收集。 flatMapping()
方法返回在收集元素之前应用扁平映射方法的收集器。指定的扁平映射方法被应用到流的每个元素,并且从扁平映射器返回的流的元素的累积。
在JDK 9中,下划线(_)是一个关键字,不能将其本身用作单字符标识符,例如变量名称,方法名称,类型名称等。但是,仍然可以使用下划线多个字符的标识符名称。
JDK 9删除了限制,必须使用try-with-resource块为要管理的资源声明新变量。现在,可以使用final
或有效的final
变量来引用资源由try-with-resources块来管理。
只要推断的类型是可表示的,JDK 9就添加了对匿名类中的钻石操作符的支持。
可以在接口中具有非抽象非默认实例方法或静态方法的私有方法。
JDK 9允许在私有方法上使用@SafeVarargs注解。 JDK 8已经允许它在构造方法,stati方法和
final`方法上。
JDK 9向ProcessBuilder.Redirect
嵌套类添加了DISCARD
的新常量。它的类型是ProcessBuilder.Redirect
。当要丢弃输出时,可以将其用作子进程的输出和错误流的目标。实现通过写入操作系统特定的“空文件”来丢弃输出。
JDK 9为Math
和StrictMath
类添加了几种方法来支持更多的数学运算,如floorDiv(long x, int y)
,floorMod(long x, int y)
,multiplyExact(long x, int y)
,multiplyFull(int x, int y)
,multiplyHigh(long x, long y)
等。
JDK 9向java.util.Optional
类添加了三个方法:ifPresentOrElse()
,of()
和stream()
。 ifPresentOrElse()
方法可以提供两个备选的操作。如果存在值,则执行一个操作。否则,它执行另一个操作。如果存在值,则or()
方法返回Optional
。否则返回指定Supplier
返回的可选项。 stream()
方法返回包含可选中存在的值的元素的顺序流。如果Optional
为空,则返回一个空的流。 stream()
方法在扁平映射中(flat maps)很有用。
JDK 9向Thread
类添加了一个新的静态onSpinWai()
方法。对处理器来说,这是一个纯粹的提示,即调用者线程暂时无法继续,因此可以优化资源使用。在自旋循环中使用它。
Time API在JDK 9中得到了一个提升。在Duration
,LocalDate
,LocalTime
和OffsetTime
类中添加了几种方法。LocalDate
类接收到一个新的datesUntil()
方法,它返回两个日期之间的日期流,以一天或给定期间的增量。 Time API中有几个新的格式化符号。
Matcher
类新增几个现有方法的重载版本,它们用于与StringBuffer
一起工作,以支持使用StringBuilder
。一个为results()
的新方法返回一个Stream<MatchResult>
。 Objects
类收到了几个新的实用方法来检查数组和集合的范围。
ava.util.Arrays
新增了几种方法,可以比较数组和部分数组的相等性和不匹配性。
Javadoc在JDK 9中得到了增强。它支持HTML5。可以使用一个新的选项-html5
与javadoc工具一起生成HTML5格式的Javadoc。对所有模块,包,类型,成员和形式参数类型的名称进行索引,并使用新的搜索功能进行搜索。 Javadoc在每个主页的右上角显示一个搜索框,可用于搜索索引条款。还可以在Javadoc中使用一个新的标签@index
来创建用户定义的术语。使用客户端JavaScript执行搜索,并且不进行服务器通信。
许多浏览器供应商已经删除了对Java浏览器插件的支持,或者将在不久的将来删除它。记住这一点,JDK 9不赞成使用Applet API。 java.applet包和javax.swing.JApplet
类中的所有类型已被弃用。 appletviewer工具也已被弃用。
JDK 6通过java.awt.Desktop
类添加了对平台特定桌面功能的有限支持,例如在用户默认浏览器中打开URI,在用户默认邮件客户端中打开mailto URI,以及使用注册的应用打开,编辑和打印文件。如果Java SE 9在当前平台上可用,许多系统和应用程序事件通知都会提供特定于平台的桌面支持,并为其添加了公共API支持。为了支持这么多新的桌面功能,Java SE 9向java.desktop模块添加了一个新的包java.awt.desktop。 java.awt.Desktop
类也增加了很多新的方法。在JDK 9中,Desktop API支持24个平台特定的桌面操作和通知,例如当附加的显示进入或退出节电模式,系统进入睡眠模式或系统唤醒后的通知等。
为了解决反序列化带来的安全风险,JDK 9引入了一个对象输入过滤器的概念,可以用来验证被反序列化的对象,如果没有通过测试,则可以停止反序列化过程。对象输入过滤器是新接口java.io.ObjectInputFilter
的实例。可以指定可以在反序列化任何对象时使用的全系统全局过滤器。可以使用新的jdk.serialFilter系统属性,使用JAVA_HOME\conf\security\java.security文件中jdk.serialFilter的属性,或使用ObjectInputFilter.Config
类的setSerialFilter()
方法来指定全局过滤器。可以使用其setObjectInputFilter()
方法在ObjectInputStream
上设置本地过滤器,该方法将覆盖全局过滤器。
java.io.InputStream
类新增一个称为transferTo(OutputStream out)
的方法,可用于从输入流读取所有字节,并将它们顺序写入指定的输出流。该方法不关闭任一流。 java.nio.Buffer
类接收到两个方法,duplicate()
和slice()
——可用于复制和拼接缓冲区。复制和分片缓冲区与原始缓冲区共享其内容。但是他们保持自己的位置,限定和标记,独立于原始缓冲区。