[TOC]
https://www.oracle.com/technetwork/java/javase/jdk-relnotes-index-2162236.html
JDK每个版本更新的内容
TM是英文Trademark商标的意思。
在我国,商标符号是:® 或 注 ,没有使用TM的规定,采用“先注册原则”,所以如果谁注册了某个东西为商标就可以加个商标符号。
在美国,商标采用“先使用原则”,如果产生冲突,法律(法庭)会保护优先使用者权利即使没有注册。美国一般习惯使用TM来表明:“这是一个我们已经使用的商标”
Java Community Process ,Java社区进程
JCP成立于1998年,官网,由社会各界Java组成的社区,规划和领导Java的发展,其成员可以在这里看到
Java Specification Requests,Java规范请求,由JCP成员向委员会提交的Java发展议案,经过一系列流程后,如果通过最终会体现在未来的Java中
Technology Compatibility Kit,技术兼容性测试
如果一个平台型程序想要宣称自己兼容Java,就必须通过TCK测试
JDK Enhancement Proposal,a process used by the OpenJDK community for collecting proposals for enhancements to the Java Development Kit.
JDK增强提案,OpenJDK社区使用的一种过程,用于收集有关Java开发工具包的增强提案。
官网
Sun公司初始设立的开发Java源码组织,是组织也是开源JDK的名字
版本号 | 名称 | 中文名 | 发布日期 |
---|---|---|---|
JDK 1.1.4 | Sparkler | 宝石 | 1997-09-12 |
JDK 1.1.5 | Pumpkin | 南瓜 | 1997-12-13 |
JDK 1.1.6 | Abigail | 阿比盖尔--女子名 | 1998-04-24 |
JDK 1.1.7 | Brutus | 布鲁图--古罗马政治家和将军 | 1998-09-28 |
JDK 1.1.8 | Chelsea | 切尔西--城市名 | 1999-04-08 |
J2SE 1.2 | Playground | 运动场 | 1998-12-04 |
J2SE 1.2.1 | none | 无 | 1999-03-30 |
J2SE 1.2.2 | Cricket | 蟋蟀 | 1999-07-08 |
J2SE 1.3 | Kestrel | 美洲红隼 | 2000-05-08 |
J2SE 1.3.1 | Ladybird | 瓢虫 | 2001-05-17 |
J2SE 1.4.0 | Merlin | 灰背隼 | 2002-02-13 |
J2SE 1.4.1 | grasshopper | 蚱蜢 | 2002-09-16 |
J2SE 1.4.2 | Mantis | 螳螂 | 2003-06-26 |
Java SE 5.0/1.5 | Tiger | 老虎 | 2004-09-30 |
Java SE 6.0/1.6 | Mustang | 野马 | 2006-04 |
Java SE 7.0/1.7 | Dolphin | 海豚 | 2011-07-28 |
Java SE 8.0/1.8 (LTS) | Spider | 蜘蛛 | 2014-03-18 |
Java SE 9.0 | 2017-09-21 | ||
Java SE 10.0 | 2018-03-21 | ||
Java SE 11.0(LTS) | 2018-09-25 | ||
Java SE 12.0 | 2019/03/19 | ||
Java SE 13.0 | 2019/09/17 | ||
Java SE 14.0 | 2020/03/17 | ||
Java SE 15.0 | |||
Java SE 16.0 | |||
Java SE 17.0(LTS) |
时间 | 事迹 |
---|---|
1995年5月23日 | Java语言诞生 |
1996年1月 | 第一个JDK-JDK1.0诞生 |
1996年4月 | 10个最主要的操作系统供应商申明将在其产品中嵌入JAVA技术 |
1996年9月 | 约8.3万个网页应用了JAVA技术来制作 |
1997年2月18日 | JDK1.1发布 |
1997年4月2日 | JavaOne会议召开,参与者逾一万人,创当时全球同类会议规模之纪录 |
1997年9月 | JavaDeveloperConnection社区成员超过十万 |
1998年2月 | JDK1.1被下载超过2,000,000次 |
1998年12月8日 | JAVA2企业平台J2EE发布 |
1999年6月 | SUN公司发布Java的三个版本:标准版、企业版和微型版(J2SE、J2EE、J2ME) |
2000年5月8日 | JDK1.3发布 |
2000年5月29日 | JDK1.4发布 |
2001年6月5日 | NOKIA宣布,到2003年将出售1亿部支持Java的手机 |
2001年9月24日 | J2EE1.3发布 |
2002年2月26日 | J2SE1.4发布,自此Java的计算能力有了大幅提升。 |
2004年9月30日18:00PM | J2SE1.5发布,是Java语言的发展史上的又一里程碑事件。为了表示这个版本的重要性,J2SE1.5更名为J2SE5.0 |
2005年6月 | JavaOne大会召开,SUN公司公开Java SE 6。此时,Java的各种版本已经更名以取消其中的数字“2”:J2EE更名为Java EE, J2SE更名为Java SE,J2ME更名为Java ME。 |
2006年11月13日 | SUN公司宣布Java全线采纳GNU General Public License Version 2,从而公开了Java的源代码。 |
2009年4月20日 | 甲骨文以现金收购Sun微系统公司,交易价格达74亿美元。 |
Oracle | 从2006年12月份Sun发布Java 6后,经过五年多的不懈努力在2011年7月底发布了Java 7正式版!这也是Sun被Oracle收购以来发行的第一个版本。而在三年后的今天,被冠名为“跳票王”的Oracle终于发布了Java 8的正式版,但对于很多开发者来说却比Java 7来的更漫长一些。主要原因还是因为Oracle原本计划在2013年发布正式版Java 8,却因受困于安全性的问题经过了两次跳票,经历9个里程碑版本。当然,我们更不愿意看到Oracle因如期发布而牺牲质量,把原先没有解决的一些缺陷的安全问题带到Java 8当中去。同时也很可能将放弃掉Lambda而导致广泛应用的可能性更小。不管怎么样,Java 8如今来了,全新“革命”而不再是“进化”的功能将会让无数开发者动容。 |
2014年3月18日 | Java8.0发布,这是继Java5.0以来变化最大的版本。一共有10大新特性。最主要的是Lambda表达式和强大的StreamAPI和新版的日期时间API,函数式接口和接口的默认方法和静态方法等。 |
2017年9月21日 | Java9的发布。Java 9的最主要目标是最大限度实现模块化以帮助人们实现积木式的应用编写。目的是帮助人们从JAR的束缚中解脱出来。该特性将贯穿整个Java库,并以单依赖图的方式重新整理依赖。Java 9会把所有三个Java开发平台统一起来,模块化特性会使得Java ME的可复用性得到增强,这将是反击Android和iOS的有力武器。 |
Java数据类型分两种:基本数据类型 和 引用数据类型(对象)
有时候我们需要将基本数据类型包装为对象进行处理
在JKD5以前我们的处理方式:
//int 转换为 Integer
int i = 10;
Integer integer = new Integer(i);
//Integer 转换为 int
Integer integer1 = new Integer(100);
int i1 = integer1.intValue();
自动拆装箱处理方式:
//int 转换为 Integer
Integer integer = 10;
//Integer 转换为 int
int i = integer;
将class反编译可以看出自动拆装箱的代码如下:
Integer integer = Integer.valueOf(10);
int i = integer.intValue();
以上就是自动拆装箱的效果,同理其余基本类型也可以自动裁装箱对应的对象。详细对应关系如下表:
基本数据类型 | 封装类 |
---|---|
int | Integer |
byte | Byte |
short | Short |
long | Long |
char | Character |
double | Double |
float | Float |
boolean | Boolean |
自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中。
自动拆箱的过程:每当需要一个值时,被装箱对象中的值就被自动地提取出来,没必要再去调用intValue()和doubleValue()方法。
自动装箱,只需将该值赋给一个类型包装器引用,java会自动创建一个对象。
自动拆箱,只需将该对象值赋给一个基本类型即可。
java——类的包装器
类型包装器有:Double,Float,Long,Integer,Short,Character和Boolean
增强for循环,新增一种循环语法,格式:for( : )
普通for与增强for循环对比如下:
List<String> list = new ArrayList<String>();
list.add("111");
list.add("222");
list.add("333");
//JDK5 以前循环需要定义下标“index”并初始化,判断是否小于集合长度并自增,循环体还需要赋值
for (int index = 0; index < list.size(); index++ ) {
String str = list.get(index);
System.out.println("str: " + str);
}
//foreach 增强for循环只需要下面代码即可完成上面的操作。
for (String str : list){
System.out.println("str:" + str);
}
反编译class文件可以看到增强for循环会被编译器自动处理如下代码:
Iterator var4 = list.iterator();
while(var4.hasNext()) {
str = (String)var4.next();
System.out.println("str:" + str);
}
具体编译成什么类型还的根据循环数据实际的数据类型,例如:
/int数组 foreach
int[] ints = new int[]{1, 2, 3, 4, 5};
for(int i : ints){
System.out.println("i: " + i);
}
//class反编译结果
int[] ints = new int[]{1, 2, 3, 4, 5};
int[] var9 = ints;
int var4 = ints.length;
for(int var5 = 0; var5 < var4; ++var5) {
int i = var9[var5];
System.out.println("i: " + i);
}
从上面代码可以大致了解foreach,它基本可以替换掉你所有用普通for循环的代码。
静态导入可以将静态方法和静态变量通过 import static 和导包一样的方式直接导入,使用的时候无需使用类名即可直接访问。
import static java.lang.System.out;
import static java.lang.Math.*;
public class ImportStaticTest {
public static void main(String[] args) {
/*
* 使用静态导入 import static java.lang.System.out;
* out.println 可以直接使用调用 而不再需要类System对象去调用
* 同时也支持*通配符
*/
out.println("max(3,5): " + max(3,5));
out.println("random(): " + random());
}
}
当传入到方法的参数不固定时,就可以使用可变参数 格式:func(数据类型... 参数名)
public class VarArgsTest {
// Tips: 和以往main方式不一样,一般这样写 public static void main(String[] args)
public static void main(String... args) {
varArgs(1);
varArgs(2,3);
// ...
varArgs(7,8,9,10,11);
}
// 可变参数的格式: 数据类型... 参数名
public static void varArgs(int... ints) {
for (int i : ints){
System.out.println(i);
}
}
}
可变参数必须放在方法参数的最后一个并且有且只有一个
把集合里的对象元素一个一个提取出来。枚举类型使代码更具可读性,理解清晰,易于维护。枚举类型是强类型的,从而保证了系统安全性。而以类的静态字段实现的类似替代模型,不具有枚举的简单性和类型安全性。
简单的用法:JavaEnum简单的用法一般用于代表一组常用常量,可用来代表一类相同类型的常量值。
复杂用法:Java为枚举类型提供了一些内置的方法,同事枚举常量还可以有自己的方法。可以很方便的遍历枚举对象。
注意事项:
//定义枚举类型
public enum SexEnum {
MAN,WOMAN
}
// class反编译结果:
public enum SexEnum {
MAN,
WOMAN;
private SexEnum() {
}
}
Enum类常用的三个方法:
JDK5推出了printf-style格式字符串的解释器 java.util.Formatter 工具类,和C语言的printf()有些类似。
//创建对象时指定将结果输出到控制台
Formatter formatter = new Formatter(System.out);
formatter.format("x = %d , y = %s\n",1 , "test");
formatter.close();
Formatter类可以将一些特定风格的字符转换为另一种格式进行输出,给出一下常用格式转换。
Format | 类型 |
---|---|
d | 整数型 |
s | String |
f | 浮点数 |
c | Unicode字符 |
b | 布尔值 |
e | 科学计数 |
x | 整数(16进制) |
h | 散列码(16进制) |
System.out.printf 和 System.out.foramt 方法的格式化输出就是调用了Formatter工具类。其中System.out.printf 的源码实际就是调用用了System.out.foramt方法。
System.out.printf 源码如下:
public PrintStream printf(String format, Object ... args) {
return format(format, args);
}
定义:类或方法在定义时类型不确定。使用时才确定类型。
JDK5引入泛型是一个很大的功能增强,使用也比较广泛。使用多态进行数据传输时,JDK5之前使用Object传输,然后进行向下转型,这里可能在运行期强转失败抛ClassCastException异常,导致程序异常终止。引入泛型可以将此运行期异常转移到编译异常,在编写代码时就可以检测出问题。
泛型可以避免向下转型的安全隐患
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
//此处只能在运行期报ClassCastException异常。
Object obj = new String();
Integer i = (Integer) obj;
//泛型
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("efg");
//此处编译不通过,类型检测不能通过,在编译期就能解决错误。
// list.add(1);
// list.add(false);
// list.add(0.5);
}
}
泛型关键技术:
通配符问号(?)表示任意类型.如"List"表示可以存放任意对象类型的List,和List一样。
通配符可以连接限制符:extends 和 super
如:上边界List<? extends Parent> 申明的List只能存放Parent及其子类,而下边界 List<? super Child> 申明的List只能存放Child及其父类。
?extends类 . 表示泛型上限,类与方法均可使用。
?super 类 . 表示泛型下限 ,只能用在方法级别
如果使用通用类型申明一个变量,那么必须在类申明后面加上,尖括号里面的符号必须是前面申明的通用类型变量,如果有多个可以使用逗号分割如:<T,D>;
如果使用通用类型申明一个方法返回值或者方法参数,要么如上在类申明后加使用<>申明通用类型,要么在方法前申明通用类型。
//在类申明后申明通用类型T,则可以在变量、方法返回值和方法参数使用
public class Test<T> {
//在变量处使用通用类型,且并需在类申明后申明通用类型
T t;
//此处报错因为,变量通用类型必须在类申明后申明
// E e;
//在方法返回值处使用通用类型
public T getT() {
return t;
}
//在方法参数使用通用类型
public String getType(T t) {
return t.getClass().getSimpleName();
}
//方法返回值通用类型 和 方法参数通用类型 可以在方法前申明
public <E> E getE(E e) {
return e;
}
}
类型擦除(向下兼容)
泛型只存在于编译阶段,进入JVM之前,与泛型相关的信息会被完全擦除。
在JVM看来,根本就不存在泛型的概念;
泛型类在进行类型擦除时,若未指定泛型的上限,泛型相关信息会被擦除为Object类,否则,擦除为相应的类型上限。
ProcessBuilder可以用来创建操作系统进程,它的每一个实例管理着Process集合,start()方法可以创建一个新的Process实例
主要方法:
ProcessBuilder的start()方法:执行命令并返回一个Process对象;
ProcessBuilder的environment()方法:返回运行进程的环境变量Map<String,String>集合;
ProcessBuilder的directory()方法:返回工作目录;
Process的getInputStream()方法:获得进程的标准输出流;
Process的getErrorStream()方法:获得进程的错误输出流。
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
public class Test {
public static void main(String[] args) {
//创建进程
ProcessBuilder processBuilder = new ProcessBuilder("ipconfig","/all");
//获取当前进程的环境变量
Map<String, String> map = processBuilder.environment();
Process process = null;
try {
//执行 ipconfig/all 命令并返回Process对象
process = processBuilder.start();
} catch (IOException e) {
e.printStackTrace();
}
//获取进程标准输出流
InputStream in = process.getInputStream();
StringBuffer sb = new StringBuffer();
int readbytes = -1;
byte[] b = new byte[1024];
try{
while((readbytes = in.read(b)) != -1){
sb.append(new String(b,0,readbytes));
}
}catch(IOException e1){
}finally {
try{
in.close();
}catch (IOException e2){
}
}
System.out.println(sb.toString());
}
}
内省机制就是基于反射的基础,Java语言对JavaBean类属性、事件的一种缺省处理方法。
JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
符合这些特征的类,被称为JavaBean;
反射可以操作各种类的属性,而内省就是基于反射来操作JavaBean的属性。
内省中确定属性是根据 set 或 get 方法,如果只要类中有getXXX方法,或者setXXX方法,或者同时有getXXX及setXXX方法,其中getXXX方法没有方法参数,有返回值;setXXX方法没有返回值,有一个方法参数;那么内省机制就认为XXX为一个属性。
如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object),或“VO”,这些信息储存在类的私有变量中,通过set()、get()获得,如下所示:
public class User {
private String name;
private int age;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
在类User中有属性name、age和address。
通过 getName/setName来访问name属性,getAge/setAge来访问age属性,getAddress/setAddress来访问address属性,这是我们默认遵循的规则。
Java JDK中提供了一套 API用来访问某个属性的 getter/setter 方法,这就是内省.
public static void main(String[] args) throws IntrospectionException {
//获取所要操作的JavaBean信息
//BeanInfo是接口不能直接实例化,只能通过Introspector的getBeanInfo获得实例
BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
//获得JavaBean中的属性描述符,通过PropertyDescriptor可以获得属性一些信息
//属性是通过set和get方法确定的,与是否在类中定义无关,详情见文章开头
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
//获取属性名字
System.out.println(pd.getName());
//获取属性类型
System.out.println(pd.getPropertyType());
//获取get方法,如果不存在则返回null
System.out.println(pd.getReadMethod());
//获取set方法,如果不存在则返回null
System.out.println(pd.getWriteMethod());
}
}
public void insertUser(HttpServletRequest request) {
User user = new User();
BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
//需要注意参数类型匹配问题,此问题不在本文讨论范围里面
pd.getWriteMethod().invoke(user, request.getParameter(pd.getName()));
}
}
内省类库:PropertyDescriptor类库:
PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法:
//创建Person对象,并赋初始值
Person person = new Person();
person.setName("niannianjiuwang");
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("name",Person.class);
//获得属性的Class对象
System.out.println("Class: " + propertyDescriptor.getPropertyType().getSimpleName());
Method method = propertyDescriptor.getReadMethod();
System.out.println("Value: " + method.invoke(person));
System.out.println("HashCode: " + propertyDescriptor.hashCode());
JDK5提供了线程处理的高级功能,在(java.util.concurrent)包下。包括:
Lock的方法:
ReadWriteLock的方法:
Condition的方法:
ExecutorService的方法:
ArrayBlockingQueue的方法:
ConcurrentHashMap相当于一个HashMap集合,但前者是线程安全的,所以性能上比后者略低。
CopyOnWriteArrayList相当于一个ArrayList集合,前者其所有可变操作(add和set等)都是通过对底层的数组进行一次复制来实现,所以代价非常昂贵。
Semaphore的方法:
在JDK5中使用Bean监控和管理Java虚拟机,java.lang.management.ManagementFactory是管理Bean的工厂类,通过它的get系列方法能够获得不同的管理Bean的实例。
ManagementFactory的方法:
MemoryMXBean对象:该Bean用于管理Java虚拟机的内存系统,一个Java虚拟机具有一个实例。
ClassLoadingMXBean对象:该Bean用于管理Java虚拟机的类加载系统,一个Java虚拟机具有一个实例。
TreadMXBean对象:该Bean用于管理Java虚拟机的线程系统,一个Java虚拟机具有一个实例。
RuntimeMXBean对象:该Bean用于管理Java虚拟机的线程系统,一个Java虚拟机具有一个实例。
OperatingSystemMXBean对象:该Bean用于管理操作系统,一个Java虚拟机具有一个实例。
CompilationMXBean对象:该Bean用于管理Java虚拟机的编译系统,一个Java虚拟机具有一个实例。
GarbageCollectorMXBean对象:该Bean用于管理Java虚拟机的垃圾回收系统,一个Java虚拟机具有一个或者多个实例。
import java.lang.management.*;
import java.util.List;
public class Test {
public static void main(String[] args){
//Java虚拟机的内存系统
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
System.out.println("虚拟机的堆内存使用量: " + memoryMXBean.getHeapMemoryUsage());
System.out.println("虚拟机的非堆内存使用量: " + memoryMXBean.getNonHeapMemoryUsage());
//Java虚拟机的类加载系统
ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
System.out.println("当前加载到Java虚拟机中的类的数量: " + classLoadingMXBean.getLoadedClassCount());
System.out.println("自Java虚拟机开始执行到目前已经加载的类的总数: " + classLoadingMXBean.getTotalLoadedClassCount());
//Java虚拟机的线程系统
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
System.out.println("当前线程的总CPU时间: " + threadMXBean.getCurrentThreadCpuTime());
System.out.println("当前活动线程的数目,包括守护线程和非守护线程: " + threadMXBean.getThreadCount());
//Java虚拟机的线程系统
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
System.out.println("当前Java库路径: " + runtimeMXBean.getLibraryPath());
System.out.println("当前Java虚拟机实现提供商: " + runtimeMXBean.getVmVendor());
//操作系统
OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
System.out.println("当前Java虚拟机可以使用的处理器数目: " + operatingSystemMXBean.getAvailableProcessors());
System.out.println("当前操作系统名称: " + operatingSystemMXBean.getName());
//Java虚拟机的编译系统
CompilationMXBean compilationMXBean = ManagementFactory.getCompilationMXBean();
System.out.println("当前(JIT)编译器的名称: " + compilationMXBean.getName());
System.out.println("当前即时(JIT)编译器的名称: " + compilationMXBean.getTotalCompilationTime());
//Java虚拟机的垃圾回收系统
List<GarbageCollectorMXBean> garbageCollectorMXBeanList = ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeanList) {
System.out.println("当前垃圾收集器的名字: " + garbageCollectorMXBean.getName());
System.out.println("当前垃圾收集器累计回收总次数: " + garbageCollectorMXBean.getCollectionCount());
System.out.println("当前垃圾收集器累计回收总时间: " + garbageCollectorMXBean.getCollectionTime());
}
}
}
元数据也可以叫注解,这个名字估计容易理解,格式:@注解名
注解的作用范围,可以通过java.lang.annotation.ElementType查看:
TYPE:类、接口(包括注释类型)或enum声明
FIELD:字段声明(包括enum常量)
METHOD:方法申明
PARAMETER:参数申明
CONSTRUCTOR:构造器申明
LOCAL_VARIABLE:局部变量申明
ANNOTATION_TYPE:注解类型申明
PACKAGE:包申明
JDK内置三种标准注解:
@Override: 注解只能使用在方法上,表示当前的方法定义将覆盖超类中的方法。如果你不小心拼写错误,或者方法签名对不上被覆盖的方法,编译器就会发出错误的提示
@Deprecated: 注解可使用在构造器、字段、局部变量、方法、包、类接口以及枚举上,表示被弃用,不鼓励使用,编译器会发出警告信息。通常是因为它是危险的,或则因为有更好的选择。
@SuppressWarnings:注解可以使用在构造器、字段、局部变量、方法、类接口以及枚举上,必须指定value值,关闭不当的编译器警告信息。告诉编译器不提示某某警告信息。
注意的几个问题:
当注解的元素没有默认值的时候,在使用的时候必须为其指定初始值
如果注解元素有了初始值,那么在使用的时候可以为其赋新的值,否则将使用默认值
一个较为特殊的情况:注解元素当且仅当其只有一个元素且名称为value时,在使用该注解的时候为其赋值时可以不用写属性(元素)名称
元注解:
java内置了4种元注解,元注解负责注解其它的注解,可以理解成java中用来注解Annotation的Annotation
@Retention: 保留策略,表示注解有多长保留,先了解JAVA文件的三个时期:SOURCE 源文件期(*.java文件) -> CLASS 编译器编译期(*.class文件) -> RUNTIME
jvm运行时期。
@Target: 表示注解使用的上下文,TYPE、FIELD、METHOD、PARAMETER、CONSTRUCTOR、LOCAL_VARIABLE、ANNOTATION_TYPE和PACKAGE。详细说明返回看注解的作用范围。
@Documented: 表示将被javadoc记录。
@Inherited: 表明注释类型是自动继承的。如果一个继承的元注释出现在注释类型上声明,用户在一个类上查询注释类型声明,类声明没有这种类型的注释,然后该类的超类将自动被查询注释类型。这个过程将会重复直到这个注释类型被找到,或者类层次结构的顶部(对象)是达到了。如果没有超类有这种类型的注释,那么查询将表明的类没有这样的注释。
提供动态语言支持、提供编译API和卫星HTTP服务器API,改进JVM的锁,同步垃圾回收,类加载
JDK6 改动最大的就是java GUI界面的显示,JDK6支持最新的windows vista系统的Windows Aero视图效果,而JDK5不支持。
JDK6在java.awt包下新增了两个类:Desktop和SystemTray
允许 Java 应用程序启动已在本机桌面上注册的关联应用程序来处理 URI 或文件。
Desktop类的主要方法:
browse(URI uri): 使用默认浏览器打开uri资源。
checkActionSupport(Action actionType): 检查是否支持的Action。
open(File file): 启动关联应用程序来打开文件。
edit(File file): 启动关联编辑器应用程序并打开一个文件编辑。
print(File file): 使用关联应用程序打印文件。
mail(): 启动用户默认邮件客户端的邮件组合窗口。
mail(URI mailtoURI): 启动用户默认邮件客户端的邮件组合窗口, 填充由 mailto:URI 指定的消息字段。
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.net.URI;
public class Test {
public static void main(String[] args) throws IOException {
//先判断当前平台是否支持Desktop类
if (Desktop.isDesktopSupported()) {
//获取Desktop实例
Desktop desktop = Desktop.getDesktop();
//使用默认浏览器打开链接
desktop.browse(URI.create("http://www.cnblogs.com/peter1018"));
// 打开指定文件/文件夹
desktop.open(new File("D:\\"));
//......
//其他方法可以自行演示...
}else {
System.out.println("当前平台不支持 Desktop类!");
}
}
}
代表一个系统托盘桌面。在微软的Windows上,它被称为“任务栏”状态区域,在Gnome上,它被称为“通知”在KDE上,它被称为“系统托盘”。该系统托盘由在桌面上运行的所有应用程序共享。
SystemTray类的主要方法:
isSupported() : 检测系统是否支持SystemTray类。
getSystemTray() : 获得SystemTray实例。
add(TrayIcon trayIcon): 在“系统托盘”上添加一个“TrayIcon”。TrayIcon对象代表一个托盘图标,它可以有一个工具提示(文本),一个图像,一个弹出框菜单,以及一组与之相关的侦听器。托盘图标一旦出现,就会在系统托盘中显示。
remove(TrayIcon trayIcon): 删除指定的“TrayIcon”。
getTrayIcons(): 返回一个由这个托盘添加到托盘上的所有图标的数组应用程序。
getTrayIconSize(): 以像素为单位,返回在系统托盘中占据的一个托盘图标的大小。
addPropertyChangeListener(String propertyName,PropertyChangeListener listener): 将 PropertyChangeListener 添加到监听器
removePropertyChangeListener(String propertyName,PropertyChangeListener listener): 将PropertyChangeListener 从监听器移除
getPropertyChangeListeners(String propertyName) : 返回所有已关联的监听器数组
import javax.swing.*;
import java.awt.*;
public class Test {
public static void main(String[] args) throws AWTException {
//先判断当前平台是否支持SystemTray类
if (SystemTray.isSupported()) {
//获取SystemTray实例
SystemTray systemTray = SystemTray.getSystemTray();
//获得托盘显示图标
ImageIcon imageIcon=new ImageIcon("D:\\icon.jpg");
//获得Image对象
Image icon=imageIcon.getImage();
//任务栏程序托盘图标
TrayIcon trayicon = new TrayIcon(icon,"JAVA系统托盘");
//关键点,设置托盘图标的自适应属性,这样才能在系统显示托盘处正常显示出需要的图片。
trayicon.setImageAutoSize(true);
//添加系统托盘
systemTray.add(trayicon);
//......
//其他方法可以自行演示...
//移除系统托盘
systemTray.remove(trayicon);
}else {
System.out.println("当前平台不支持 SystemTray类!");
}
}
}
JAXB是Java Architecture for XML Binding的缩写,可以将一个Java对象转变成为XML格式,反之亦然。我们把对象与关系数据库之间的映射称为ORM, 其实也可以把对象与XML之间的映射称为OXM(Object XML Mapping)。原来JAXB是Java EE的一部分,在JDK6中,SUN将其放到了Java SE中,这也是SUN的一贯做法。JDK6中自带的这个JAXB版本是2.0, 比起1.0(JSR 31)来,JAXB2(JSR 222)用JDK5的新特性Annotation来标识要作绑定的类和属性等,这就极大简化了开发的工作量。实际上,在Java EE 5.0中,EJB和Web Services也通过Annotation来简化开发工作。另外,JAXB2在底层是用StAX(JSR 173)来处理XML文档。
重要的注解和说明
注解 | 说明 |
---|---|
@XmlRootElement | 将类或enum类型映射到XML元素,类名或名作为根节点 |
@XmlAttribute | 将JavaBean属性映射到XML属性 |
@XmlElement | 将JavaBean属性映射到源自属性名的XML元素 |
@XmlAnyAttribute | 将JavaBean属性映射到通配符属性的映射 |
@XmlAnyElement | 将JavaBean属性映射到XML infoset或JAXB |
@XmlElements | 一个用于多XmlElement注解的容器。 |
@XmlID | 将JavaBean属性映射到XML ID |
@XmlIDREF | 将JavaBean属性映射到XML IDREF |
@XmlList | 用来将一个属性映射到一个List |
@XmlSchema | 将包映射到XML名称空间 |
@XmlTransient | 该属性无需映射到XML |
Address类
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
public class Address {
@XmlAttribute
String province;
@XmlElement
String area;
@XmlElement
String street;
public Address() {}
public Address(String province, String area, String street) {
this.province = province;
this.area = area;
this.street = street;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", area='" + area + '\'' +
", street='" + street + '\'' +
'}';
}
}
Person类
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Person{
@XmlAttribute
private String name;
@XmlElement
private int age;
@XmlElement
private Address address;
public Person() {
}
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
测试类:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws JAXBException, IOException {
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
//根据Person对象转换为person.xml文件
Marshaller marshaller = jaxbContext.createMarshaller();
Address address = new Address("广东省","深圳市","宝安区");
Person person = new Person("niannianjiuwang", 20, address);
FileWriter fileWriter = new FileWriter("D:\\person.xml");
marshaller.marshal(person, fileWriter);
//根据person.xml文件转换为对象
FileReader fileReader = new FileReader("D:\\person.xml");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Person personNew = (Person) unmarshaller.unmarshal(fileReader);
System.out.println(personNew);
}
}
person.xml文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person name="niannianjiuwang">
<age>20</age>
<address province="广东省">
<area>深圳市</area>
<street>宝安区</street>
</address>
</person>
StAX的来历 :
在JAXP1.3(JSR 206)有两种处理XML文档的方法:DOM(Document Object Model)和SAX(Simple API for XML).由于JDK6.0中的JAXB2(JSR 222)和JAX-WS 2.0(JSR 224)都会用到StAX所以Sun决定把StAX加入到JAXP家族当中来,并将JAXP的版本升级到1.4(JAXP1.4是JAXP1.3的维护版本). JDK6里面JAXP的版本就是1.4。
StAX简介:
StAX是Streaming API for XML的缩写,它包含在2004年3月的JSR 173 中。StAX是JDK6.0中包含的新特性。
在推式模型中,直到整个XML文件全部被解析,解析器才会产生解析事件。而拉式解析由应用程序来控制,也就是说解析事件由应用程序产生。这就意味着,你可以暂缓解析、解析时跳过某个元素或者同时解析多个文件。用DOM解析式要先将XML文件解析成DOM结构,因此降低了解析效率。使用StAX,解析事件在XML文件解析过程中产生。
下面是各种解析方法之间的比较:
XML Parser API Feature Summary
Feature | StAX | SAX | DOM | TrAX |
---|---|---|---|---|
API Type | Pull, streaming | Pull, streaming | In memory tree | XSLT Rule |
Ease of Use | High | Medium | High | Medium |
XPath Capability | No | No | Yes | Yes |
CPU and Memory Efficiency | Good | Good | Varies | Varies |
Forward Only | Yes | Yes | No | No |
Read XML | Yes | Yes | Yes | Yes |
Write XML | Yes | No | Yes | Yes |
Create, Read, Update, Delete | No | No | Yes | No |
StAX API同样也在JWSDP(Java Web Services Developer Pack )1.6中得到实现,你可以在包javax.xml.stream 中找到它。XMLStreamReader接口用来解析XML文件。XMLStreamWriter接口用来生成XML文件,XMLEventReader用一个对象事件迭代器来解析XML事件。与之相反,XMLStreamReader采用的是游标机制。
import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) throws FileNotFoundException, XMLStreamException {
writeXMLByStAX();//用XMLStreamWriter写xml文档
readXMLByStAX();//用XMLEventReader解析xml文档
}
/**
* 通过StAX读XML
*/
private static void readXMLByStAX() throws XMLStreamException, FileNotFoundException {
XMLInputFactory xmlif = XMLInputFactory.newInstance();
XMLEventReader xmler = xmlif.createXMLEventReader(new FileInputStream("D:\\write.xml"));
XMLEvent event;
StringBuffer parsingResult = new StringBuffer();
while (xmler.hasNext()) {
event = xmler.nextEvent();
parsingResult.append(event.toString());
}
System.out.println(parsingResult);
}
/**
* 通过StAX写XML
*/
private static void writeXMLByStAX() throws FileNotFoundException, XMLStreamException {
XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
XMLStreamWriter xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(new FileOutputStream("D:\\write.xml"));
// 写入默认的 XML 声明到xml文档
xmlStreamWriter.writeStartDocument();
// 写入注释到xml文档
xmlStreamWriter.writeComment("testing comment");
// 写入一个catalogs根元素
xmlStreamWriter.writeStartElement("catalogs");
xmlStreamWriter.writeNamespace("myUrl", "http://www.cnblogs.com/peter1018");
xmlStreamWriter.writeAttribute("name","niannianjiuwang");
// 写入子元素catalog
xmlStreamWriter.writeStartElement("http://www.cnblogs.com/peter1018", "catalog");
xmlStreamWriter.writeAttribute("id","StAX");
xmlStreamWriter.writeCharacters("Apparel");
// 写入catalog元素的结束标签
xmlStreamWriter.writeEndElement();
// 写入catalogs元素的结束标签
xmlStreamWriter.writeEndElement();
// 结束 XML 文档
xmlStreamWriter.writeEndDocument();
xmlStreamWriter.close();
}
}
输出结果:
write.xml文件内容:
<?xml version="1.0" ?><!--testing comment--><catalogs xmlns:myUrl="http://www.cnblogs.com/peter1018" name="niannianjiuwang"><myUrl:catalog id="StAX">Apparel</myUrl:catalog></catalogs>
控制台打印结果:
<?xml version="1.0" encoding='UTF-8' standalone='no'?><!--testing comment--><catalogs name='niannianjiuwang' xmlns:myUrl='http://www.cnblogs.com/peter1018'><['http://www.cnblogs.com/peter1018']:myUrl:catalog id='StAX'>Apparel</['http://www.cnblogs.com/peter1018']:myUrl:catalog></catalogs>ENDDOCUMENT
Java编程语言编译器javac读取以Java编程语言编写的源文件,并将它们编译为字节码class文件。或者,编译器也可以使用注解找到源文件和类文件并使用comiler API。编译器是一个命令行工具,但也可以使用Java compiler API调用。原话:(官网介绍)
我们可以用JDK6 的Compiler API(JSR 199)去动态编译Java源文件,Compiler API结合反射功能就可以实现动态的产生Java代码并编译执行这些代码,有点动态语言的特征。这个特性对于某些需要用到动态编译的应用程序相当有用, 比如JSP Web Server,当我们手动修改JSP后,是不希望需要重启Web Server才可以看到效果的,这时候我们就可以用Compiler API来实现动态编译JSP文件,当然,现在的JSP Web Server也是支持JSP热部署的,现在的JSP Web Server通过在运行期间通过Runtime.exec或ProcessBuilder来调用javac来编译代码,这种方式需要我们产生另一个进程去做编译工作,不够优雅而且容易使代码依赖与特定的操作系统;Compiler API通过一套易用的标准的API提供了更加丰富的方式去做动态编译,而且是跨平台的。
运行代码之前必须在D目录下存放TestObject.java文件
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardJavaFileManager = compiler.getStandardFileManager(null,null,null);
Iterable<? extends JavaFileObject> sourcefiles = standardJavaFileManager.getJavaFileObjects("D:\\TestObject.java");
compiler.getTask(null, standardJavaFileManager, null, null, null, sourcefiles).call();
standardJavaFileManager.close();
}
}
输出结果:会在D目录下生成TestObject.class文件。
JDK6 提供了一个简单的Http Server API,据此我们可以构建自己的嵌入式Http Server,它支持Http和Https协议,提供了HTTP1.1的部分实现,没有被实现的那部分可以通过扩展已有的Http Server API来实现,必须自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给 HttpHandler实现类的回调方法。
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import java.io.*;
public class TestHandler implements HttpHandler {
@Override
public void handle(HttpExchange httpExchange) throws IOException {
System.out.println("==进入Hadnler方法");
String responseMsg = "OK"; //响应信息
InputStream in = httpExchange.getRequestBody(); //获得输入流
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String temp = null;
while((temp = reader.readLine()) != null) {
System.out.println("client request:"+temp);
}
httpExchange.sendResponseHeaders(200, responseMsg.length()); //设置响应头属性及响应信息的长度
OutputStream out = httpExchange.getResponseBody(); //获得输出流
out.write(responseMsg.getBytes());
out.flush();
httpExchange.close();
}
}
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.spi.HttpServerProvider;
import java.io.IOException;
import java.net.InetSocketAddress;
public class Test {
public static void main(String[] args) throws IOException {
//启动服务,监听来自客户端的请求
HttpServerProvider provider = HttpServerProvider.provider();
//监听8888端口,能同时接受100个请求
HttpServer httpserver =provider.createHttpServer(new InetSocketAddress(8888), 100);
//将 /test 请求交给 TestHandler 处理器处理
httpserver.createContext("/test", new TestHandler());
httpserver.setExecutor(null);
httpserver.start();
System.out.println("server started");
}
}
插入式注解处理API(JSR 269)提供一套标准API来处理Annotations(JSR 175)。实际上JSR 269不仅仅用来处理Annotation,它还建立了Java 语言本身的一个模型,它把method, package, constructor, type, variable, enum,,annotation等Java语言元素映射为Types和Elements, 从而将Java语言的语义映射成为对象,我们可以在javax.lang.model包下面可以看到这些类. 所以我们可以利用JSR 269提供的API来构建一个功能丰富的元编程(metaprogramming)环境。JSR 269用Annotation Processor在编译期间而不是运行期间处理Annotation, Annotation Processor相当于编译器的一个插件,所以称为插入式注解处理。如果Annotation Processor处理Annotation时(执行process方法)产生了新的Java代码,编译器会再调用一次Annotation Processor,如果第二次处理还有新代码产生,就会接着调用Annotation Processor,直到没有新代码产生为止。每执行一次process()方法被称为一个"round",这样整个Annotation processing过程可以看作是一个round的序列,JSR 269主要被设计成为针对Tools或者容器的API。
举个例子,我们想建立一套基于Annotation的单元测试框架(如TestNG),在测试类里面用Annotation来标识测试期间需要执行的测试方法,如下所示:
@TestMethod
public void testCheckName(){
//do something here
}
这时我们就可以用JSR 269提供的API来处理测试类,根据Annotation提取出需要执行的测试方法。
另一个例子是如果我们出于某种原因需要自行开发一个符合Java EE 5.0的Application Server(当然不建议这样做),我们就必须处理Common Annotations(JSR 250),Web Services Metadata(JSR 181)等规范的Annotations,这时可以用JSR 269提供的API来处理这些Annotations. 在现在的开发工具里面,Eclipse 3.3承诺将支持JSR 269
下面我用代码演示如何来用JSR 269提供的API来处理Annotations和读取Java源文件的元数据(metadata)
@SupportedAnnotationTypes("PluggableAPT.ToBeTested")//可以用"*"表示支持所有Annotations
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class MyAnnotationProcessor extends AbstractProcessor {
private void note(String msg) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg);
}
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//annotations的值是通过@SupportedAnnotationTypes声明的且目标源代码拥有的所有Annotations
for(TypeElement te:annotations){
note("annotation:"+te.toString());
}
Set<? extends Element> elements = roundEnv.getRootElements();//获取源代码的映射对象
for(Element e:elements){
//获取源代码对象的成员
List<? extends Element> enclosedElems = e.getEnclosedElements();
//留下方法成员,过滤掉其他成员
List<? extends ExecutableElement> ees = ElementFilter.methodsIn(enclosedElems);
for(ExecutableElement ee:ees){
note("--ExecutableElement name is "+ee.getSimpleName());
List<? extends AnnotationMirror> as = ee.getAnnotationMirrors();//获取方法的Annotations
note("--as="+as);
for(AnnotationMirror am:as){
//获取Annotation的值
Map<? extends ExecutableElement, ? extends AnnotationValue> map= am.getElementValues();
Set<? extends ExecutableElement> ks = map.keySet();
for(ExecutableElement k:ks){//打印Annotation的每个值
AnnotationValue av = map.get(k);
note("----"+ee.getSimpleName()+"."+k.getSimpleName()+"="+av.getValue());
}
}
}
}
return false;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface ToBeTested{
String owner() default "Chinajash";
String group();
}
编译以上代码,然后再创建下面的Testing对象,不要编译Testing对象,我在后面会编译它
public class Testing{
@ToBeTested(group="A")
public void m1(){
}
@ToBeTested(group="B",owner="QQ")
public void m2(){
}
@PostConstruct//Common Annotation里面的一个Annotation
public void m3(){
}
}
下面我用以下命令编译Testing对象
javac -XprintRounds -processor PluggableAPT.MyAnnotationProcessor Testing.java
-XprintRounds表示打印round的次数,运行上面命令后在控制台会看到如下输出:
Round 1:
input files: {PluggableAPT.Testing}
annotations: [PluggableAPT.ToBeTested, javax.annotation.PostConstruct]
last round: false
Note: annotation:PluggableAPT.ToBeTested
Note: --ExecutableElement name is m1
Note: ")
Note: ----m1.group=A
Note: --ExecutableElement name is m2
Note: ", owner="QQ")
Note: ----m2.group=B
Note: ----m2.owner=QQ
Note: --ExecutableElement name is m3
Note: --as=@javax.annotation.PostConstruct
Round 2:
input files: {}
annotations: []
last round: true
本来想用JDK6.0的Compiler API来执行上面编译命令,可是好像现在Compiler API还不支持-processor参数,运行时总报以下错误
Exception in thread "main" java.lang.IllegalArgumentException: invalid flag: -processor PluggableAPT.MyAnnotationProcessor
调用Compiler API的代码是这样的
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> sourcefiles = fileManager.getJavaFileObjects("Testing.java");
Set<String> options = new HashSet<String>();
options.add("-processor PluggableAPT.MyAnnotationProcessor");
compiler.getTask(null, fileManager, null, options, null, sourcefiles).call();
JDK6中提供 了java.io.Console类专用来访问基于字符的控制台设备。程序如果要与Windows下的cmd或者Linux下的Terminal交互,就可以用Console类代劳。但我们不总是能得到可用的Console,一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用。如果JVM是在交互式命令行(比如Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实例 。
import java.io.Console;
public class Test {
public static void main(String[] args){
Console console = System.console();
if(console!=null){//判断console是否可用
String user = new String(console.readLine("Enter user:")); //读取整行字符
String pwd = new String(console.readPassword("Enter passowrd:")); //读取密码,密码输入时不会显示
console.printf("User is:"+user+"/n");
console.printf("Password is:"+pwd+"/n");
}else{
System.out.println("JVM无法使用当前的Console");
}
}
}
在IntelliJ IDEA 中直接运行执行结果:
JVM无法使用当前的Console
在cmd里面直接 java Test 结果:红色字体是输入部分,密码后面输入默认是隐藏的
F:\test\>java Test
Enter user:niannianjiuwang
Enter passowrd:
User is:niannianjiuwang/nPassword is:123456/n
JDK6增加了对脚本语言的支持(JSR 223),原理上是将脚本语言编译成字节码,这样脚本语言也能享用Java平台的诸多优势,包括可移植性,安全等,另外,由于现在是编译成字节码后再执行,所以比原来边解释边执行效率要高很多。加入对脚本语言的支持后,对
Java语言也提供了以下好处。
Sun的JDK6实现包含了一个基于Mozilla Rhino的 脚本语言引擎,支持JavaScript,这并不是说明JDK6只支持JavaScript,任何第三方都可以自己实现一个JSR-223兼容的脚本引擎 使得JDK6支持别的脚本语言,比如,你想让JDK6支持Ruby,那你可以自己按照JSR 223的规范实现一个Ruby的脚本引擎类,具体一点,你需要实现 javax.script.ScriptEngine(简单起见,可以继承 javax.script.AbstractScriptEngine) 和 javax.script.ScriptEngineFactory 两个接口。当然,在你实现自己的脚本语引擎之前,先到 scripting.dev.java.net project 这里看看是不是有人已经帮你做了工作,这样你就可以直接拿来用。
Scripting API是用于在Java里面编写脚本语言程序的API, 在Javax.script中可以找到Scripting API,我们就是用这个API来编写JavaScript程序,这个包里面有一个ScriptEngineManager类,它是使用Scriptng API 的入口,ScriptEngineManager可以通过Jar服务发现(service discovery)机制寻找合适的脚本引擎类(ScriptEngine),使用Scripting API的最简单方式只需下面三步
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class Test {
public static void main(String[] args){
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
String script;
try {
script = "print('Hello')";
engine.eval(script);// 执行脚本
script = "1-23*9/3+77";
System.out.println(engine.eval(script).toString());// 不用对字符串做解析便可得到算式结果
engine.put("a", "一个字符串");
script = "print(a)";
engine.eval(script);// 脚本调用java对象
script = "function hello(name) { return 'Hello,' + name;}";
engine.eval(script);
Invocable inv = (Invocable) engine;
System.out.println(inv.invokeFunction("hello", "Scripting"));//java调用脚本方法
} catch (Exception e) {
e.printStackTrace();
}
}
}
Common annotations原本是Java EE 5.0(JSR 244)规范的一部分,现在SUN把它的一部分放到了Java SE 6.0中。随着Annotation元数据功能(JSR 175)加入到Java SE 5.0里面,很多Java 技术(比如EJB,Web Services)都会用Annotation部分代替XML文件来配置运行参数(或者说是支持声明式编程,如EJB的声明式事务), 如果这些技术为通用目的都单独定义了自己的Annotations,显然有点重复建设, 所以,为其他相关的Java技术定义一套公共的Annotation是有价值的,可以避免重复建设的同时,也保证Java SE和Java EE 各种技术的一致性。
下面列举出Common Annotations 1.0里面的10个Annotations Common Annotations
注解 | 说明 |
---|---|
@Generated | 生成的注释用于标记已生成的源代码。 |
@Resource | 用于标注所依赖的资源,容器据此注入外部资源依赖,有基于字段的注入和基于setter方法的注入两种方式 。 |
@Resources | 同时标注多个外部依赖,容器会把所有这些外部依赖注入 。 |
@PostConstruct | 标注当容器注入所有依赖之后运行的方法,用来进行依赖注入后的初始化工作,只有一个方法可以标注为PostConstruct 。 |
@RunAs | 执行期间应用程序的角色 。 |
@PreDestroy | 当对象实例将要被从容器当中删掉之前,要执行的回调方法要标注为RunAs用于标注用什么安全角色来执行被标注类的方法,这个安全角色必须和Container 的Security角色一致的。 |
@RolesAllowed | 用于标注允许执行被标注类或方法的安全角色,这个安全角色必须和Container 的Security角色一致的 。 |
@PermitAll | 允许所有角色执行被标注的类或方法 。 |
@DenyAll | 不允许任何角色执行被标注的类或方法,表明该类或方法不能在Java EE容器里面运行 。 |
@DeclareRoles | 用来定义可以被应用程序检验的安全角色,通常用isUserInRole来检验安全角色 。 |
注意:
提供GI收集器、加强对非Java语言的调用支持(JSR-292,升级类加载架构
https://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html
在Java SE 7,整数类型(byte,short,int 和 long)也可以使用二进制数。要指定二进制,请添加前缀0b或0B编号。以下示例显示了二进制:
// 一个 8-bit 'byte' 值:
byte aByte = (byte)0b00100001;
// 一个 16-bit 'short' 值:
short aShort = (short)0b1010000101000101;
// 一些 32-bit 'int' 值:
int anInt1 = 0b10100001010001011010000101000101;
int anInt2 = 0b101;
int anInt3 = 0B101; // B可以是大写 或 小写.
// 一个 64-bit 'long' 值。 注意 'L' 后缀:
long aLong = 0b1010000101000101101000010100010110100001010001011010000101000101L;
二进制可以使数据之间的关系比以十六进制或八进制更明显。例如,以下数组中的每个连续数字都移动一位:
public static final int [] phases = {
0b00110001,
0b01100010,
0b11000100,
0b10001001,
0b00010011,
0b00100110,
0b01001100,
0b10011000
}
在十六进制中,数字之间的关系并不明显:
public static final int[] phases = {
0x31, 0x62, 0xC4, 0x89, 0x13, 0x26, 0x4C, 0x98
}
您可以在代码中使用二进制常量来验证一个规范文档,(例如假想的8位微处理器的模拟器)进行验证:
public State decodeInstruction(int instruction, State state) {
if ((instruction & 0b11100000) == 0b00000000) {
final int register = instruction & 0b00001111;
switch (instruction & 0b11110000) {
case 0b00000000: return state.nop();
case 0b00010000: return state.copyAccumTo(register);
case 0b00100000: return state.addToAccum(register);
case 0b00110000: return state.subFromAccum(register);
case 0b01000000: return state.multiplyAccumBy(register);
case 0b01010000: return state.divideAccumBy(register);
case 0b01100000: return state.setAccumFrom(register);
case 0b01110000: return state.returnFromCall();
default: throw new IllegalArgumentException();
}
} else {
final int address = instruction & 0b00011111;
switch (instruction & 0b11100000) {
case 0b00000000: return state.jumpTo(address);
case 0b00100000: return state.jumpIfAccumZeroTo(address);
case 0b01000000: return state.jumpIfAccumNonzeroTo(address);
case 0b01100000: return state.setAccumFromMemory(address);
case 0b10100000: return state.writeAccumToMemory(address);
case 0b11000000: return state.callTo(address);
default: throw new IllegalArgumentException();
}
}
}
您可以使用二进制来使位图更具可读性:
public static final short[] HAPPY_FACE = {
(short)0b0000011111100000,
(short)0b0000100000010000,
(short)0b0001000000001000,
(short)0b0010000000000100,
(short)0b0100000000000010,
(short)0b1000011001100001,
(short)0b1000011001100001,
(short)0b1000000000000001,
(short)0b1000000000000001,
(short)0b1001000000001001,
(short)0b1000100000010001,
(short)0b0100011111100010,
(short)0b0010000000000100,
(short)0b0001000000001000,
(short)0b0000100000010000,
(short)0b0000011111100000
}
Java编译器通过switch使用String对象的 if-then-else 语句比链式语句生成通常更高效的字节码。
try-with-resources可以自动关闭相关的资源(只要该资源实现了AutoCloseable接口,jdk7为绝大部分资源对象都实现了这个接口)
您可以在try-with-resources语句中声明一个或多个资源。以下示例:
public static void writeToFileZipFileContents(String zipFileName, String outputFileName)
throws java.io.IOException {
java.nio.charset.Charset charset = java.nio.charset.Charset.forName("US-ASCII");
java.nio.file.Path outputFilePath = java.nio.file.Paths.get(outputFileName);
// Open zip file and create output file with try-with-resources statement
try (
java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
) {
// Enumerate each entry
for (java.util.Enumeration entries = zf.entries(); entries.hasMoreElements();) {
// Get the entry name and write it to the output file
String newLine = System.getProperty("line.separator");
String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine;
writer.write(zipEntryName, 0, zipEntryName.length());
}
}
}
当跟随它的代码块正常结束或由于异常终止时,将按照BufferedWriter再ZipFile对象此顺序自动调用close方法。请注意,close资源的方法按照其创建的相反顺序进行调用。
注意:try-with-resources语句可以像普通try语句一样拥有catch和finally代码块。在try-with-resources语句中,任何catch或finally块在声明的资源关闭后才运行。
可以在try-with-resources语句的代码块中抛出异常。在该示例中writeToFileZipFileContents,可以从该try块中引发异常,并且try在尝试关闭ZipFile和BufferedWriter对象时最多可以从 try-with-resources 语句中抛出两个异常。如果从try块中抛出异常,并且从try-with-resources语句抛出一个或多个异常,那么从try-with-resources语句抛出的异常将被抑制,并且该块引发的异常将被writeToFileZipFileContents方法抛出。您可以通过Throwable.getSuppressed从该try块引发的异常中调用方法来检索这些抑制的异常。
请参阅Javadoc AutoCloseable和Closeable接口以获取实现这些接口之一的类的列表。该Closeable接口继承了AutoCloseable接口。接口Closeable的close方法抛出IOException异常,而接口AutoCloseable的close方法抛出Exception异常。因此,AutoCloseable接口的子类可以重写此close方法的行为来抛出特殊的异常,例如IOException根本没有异常。
catch (IOException|SQLException ex) {
logger.log(ex);
throw ex;
}
与早期版本的JDK相比,JDK7 编译器对重新产生的异常执行更精确的分析。这使您可以在throws方法声明的子句中指定更具体的异常类型。
static class FirstException extends Exception { }
static class SecondException extends Exception { }
public void rethrowException(String exceptionName) throws Exception {
try {
if (exceptionName.equals("First")) {
throw new FirstException();
} else {
throw new SecondException();
}
} catch (Exception e) {
throw e;
}
}
这个例子的try块可能会抛出FirstException或者SecondException。假设你想在rethrowException方法中throws这些异常类型。在JDK 7之前的版本中,您不能这样做。由于catch子句的异常参数e是Exception类型,并且catch块重新抛出异常参数e,所以只能在rethrowException方法抛出Exception异常类型。
在JDK7中的编译器可以通过catch块确定FirstException和SecondException异常。即使该catch子句的异常参数e类型为Exception,编译器也可以确定它是FirstException实例或者是SecondException实例:
public void rethrowException(String exceptionName)
throws FirstException, SecondException {
try {
// ...
}
catch (Exception e) {
throw e;
}
}
如果catch参数分配给catch块中的另一个值,则此分析将失效。但是,如果catch参数分配给另一个值,则必须在方法声明Exception的throws子句中指定异常类型。
详细地说,在JDK7及更高版本中,当您在catch子句中声明一个或多个异常类型并重新抛出由此catch块处理的异常时,编译器将验证重新抛出异常的类型是否满足以下条件:
JDK7编译器允许在rethrowException方法throws抛出指定Exception类型FirstException和SecondException。因为您可以重新抛出一个throws声明的任何类型的超类型。
在JDK7之前的版本中,您不能抛出该catch子句的异常参数之一的超类型。在JDK7之前的编译器Exception会在语句中生成错误未报告的异常;必须捕获或声明throw,编译器检查抛出异常的类型是否可分配给rethrowException方法声明的throws子句中声明的任何类型。然而,捕捉参数的类型e是Exception,这是一种超类型,而不是一个子类型FirstException和SecondException。
在JDK7中,任意数量的下划线字符(_)可以出现在字面值的任意位置。这个特性使您能够在字面值中分离数字组,这可以提高代码的可读性。
例如,如果您的代码包含具有许多数字的数字,则可以使用下划线字符以三个一组来分隔数字,这与使用逗号或空格等标点符号作为分隔符类似。
以下示例显示了可以在字面值中使用下划线的其他方法:
long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi = 3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;
您只能在数字之间放置下划线; 你不能在下列地方放置下划线:
float pi1 = 3_.1415F; // 无效; 不能在小数点附近加下划线
float pi2 = 3._1415F; // 无效; 不能在小数点附近加下划线
long socialSecurityNumber1
= 999_99_9999_L; // 无效; 在L后缀之前不能加下划线
int x1 = _52; // 这是一个标识符,而不是字面值
int x2 = 5_2; // OK(十进制文字)
int x3 = 52_; // 无效; 不能在文字的末尾加上下划线
int x4 = 5_______2; // OK(十进制文字)
int x5 = 0_x52; // 无效; 不能在0x基数前缀中加下划线
int x6 = 0x_52; // 无效; 不能在数字的开头加下划线
int x7 = 0x5_2; // OK(十六进制文字)
int x8 = 0x52_; // 无效; 不能在数字的末尾加上下划线
int x9 = 0_52; // OK(八进制文字)
int x10 = 05_2; // OK(八进制文字)
int x11 = 052_; // 无效; 不能在数字的末尾加上下划线
只要编译器可以从上下文中推断出类型参数,你就可以用一组空的类型参数(<>)来代替调用泛型类的构造函数所需的类型参数。这一对尖括号被非正式地称为钻石。
例如,请考虑以下变量声明:
Map<String, List<String>> myMap = new HashMap<String, List<String>>();
在JDK7中,可以使用一组空的类型参数(<>)替换构造函数的参数化类型:
Map<String, List<String>> myMap = new HashMap<>();
大多数参数化类型(如ArrayList和List)都是非具体化的类型。非具体化类型是一种在运行时不确定的类型。在编译时,非具体化类型在此过程中经历了一个称为类型擦除的过程,擦除参数类型和类型参数相关的信息。这确保了在泛型之前创建的Java库和应用程序的二进制兼容性。因为类型擦除在编译时从参数类型中删除信息,所以这些类型是非具体化的。
当参数化类型的变量引用不是该参数化类型的对象时,会发生堆污染。这种情况只有在程序执行一些操作时才会发生,从而在编译时产生不受约束的警告。一个未经检查的警告如果产生,无论是在编译时(在编译时类型检查规则的限制范围内)或运行时。一个涉及参数化类型(例如,一次转换或方法调用)的操作的正确性是无法被验证的。
思考下面的例子:
List l = new ArrayList<Number>();
List<String> ls = l; // 未经检查的警告
l.add(0, new Integer(42)); // 另一个未经检查的警告
String s = ls.get(0); // 抛出类型转换异常 ClassCastException
在类型擦除时,ArrayList类型和List类型分别变成ArrayList和List。
该ls变量具有参数化类型List,当List引用l赋值给ls时,编译器会生成未经检查的警告;如果编译器无法在编译时确定,而且JVM也无法在运行时确定l它不是一个List类型;因此,产生堆污染。
因此,在编译时,编译器会在add语句处生成另一个未经检查的警告。编译器无法确定变量l是List类型还是List类型(以及另一种发生堆污染的情况)。然而,编译器不会在get语句中产生警告或错误。此声明有效; 它调用List的get方法来获得一个String对象。相反,在运行时,get语句会抛出ClassCastException。
详细地说,当List对象l被赋值给另一个List对象ls时,就会出现堆污染情况,它有一个不同的静态类型。然而,编译器仍然允许这个赋值。它必须允许这个赋值来保证与不支持泛型的JDK版本兼容性。因为类型擦除,List和List变成List。因此,编译器允许对象l的赋值个体ls对象,因为ls是一个List类型。
另外,l.add调用该方法时会发生堆污染情况。该方法add第二参数应该是String,但实际参数是Integer。但是,编译器仍然允许这种方法调用。因为类型擦除,add方法第二个参数(List.add(int,E))变成Object。因此,编译器允许这种方法调用。因为在类型擦除之后,该l.add方法可以添加任何类型,包括Integer类型对象,因为它Object的子类。
思考下面的ArrayBuilder.addToList方法。它将类型为T的elements可变参数,添加到List listArg参数中:
import java.util.*;
public class ArrayBuilder{
public static <T> void addToList (List<T> listArg, T... elements) {
for (T x : elements) {
listArg.add(x);
}
}
public static void faultyMethod(List<String>... l) {
Object[] objectArray = l; // 有效
objectArray[0] = Arrays.asList(new Integer(42));
String s = l[0].get(0); // 抛出ClassCastException异常
}
}
import java.util.*;
public class HeapPollutionExample {
public static void main(String[] args) {
List<String> stringListA = new ArrayList<String>();
List<String> stringListB = new ArrayList<String>();
ArrayBuilder.addToList(stringListA, "Seven", "Eight", "Nine");
ArrayBuilder.addToList(stringListA, "Ten", "Eleven", "Twelve");
List<List<String>> listOfStringLists = new ArrayList<List<String>>();
ArrayBuilder.addToList(listOfStringLists, stringListA, stringListB);
ArrayBuilder.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!"));
}
}
JDK7编译器为该方法的定义生成以下警告ArrayBuilder.addToList:
warning: [varargs] Possible heap pollution from parameterized vararg type T
当编译器遇到可变参数方法时,它将可变参数形式参数转换为数组。但是,Java编程语言不允许创建参数化类型的数组。在ArrayBuilder.addToList方法中,编译器将可变参数形式参数T... elements转换为形式参数T[] elements。即数组。但是,由于类型擦除,编译器将可变参数形式参数转换为Object[] 。因此,可能存在堆污染
下面是ArrayBuilder.addToList方法的反编译结果:
public static <T> void addToList(List<T> listArg, T... elements) {
Object[] var2 = elements;
int var3 = elements.length;
for(int var4 = 0; var4 < var3; ++var4) {
T x = var2[var4];
listArg.add(x);
}
}
注意:JDK5和6编译器在ArrayBuilder.addToList调用时会生成警告HeapPollutionExample。这些编译器不会在声明上生成警告。但是,JDK7会在声明和调用上生成警告(除非这些警告被注解取代)。
该方法ArrayBuilder.faultyMethod显示了编译器为什么会警告您这些类型的方法。该方法的第一条语句将可变参数形式参数l赋值给objectArgs的Object数组:
Object[] objectArray = l;
这里可能产生堆污染。可变参数l可以赋值给objectArray数组。但是,编译器不会在此语句中生成未经检查的警告。当编译器编译List... l 为List[] l 时已经生成警告。List[]是Object[]类型的子类,所以该声明是有效的。
因此,如果您将List任何类型的对象赋值给数组objectArray,则编译器不会发出警告或错误,如此语句所示:
objectArray[0] = Arrays.asList(new Integer(42));
这个语句将List赋值给objectArray数组。
如果你调用以下方法:
ArrayBuilder.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!"));
调用以下方法,在运行时JVM会抛出ClassCastException异常。
String s = l[0].get(0); // 抛出ClassCastException
变量l存储的是List类型,但确期待是一个List类型。
如果声明了一个具体参数化的可变参数方法。且方法的体不会抛出ClassCastException或其他类似的异常。您可以使用以下几种方式来抑制编译器为这些可变参数方法生成的警告:
例如,以下ArrayBuilder类的有两个方法addToList2和addToList3:
import java.util.*;
public class ArrayBuilder {
public static <T> void addToList (List<T> listArg, T... elements) {
for (T x : elements) {
listArg.add(x);
}
}
@SuppressWarnings({"unchecked", "varargs"})
public static <T> void addToList2 (List<T> listArg, T... elements) {
for (T x : elements) {
listArg.add(x);
}
}
@SafeVarargs
public static <T> void addToList3 (List<T> listArg, T... elements) {
for (T x : elements) {
listArg.add(x);
}
}
// ...
}
import java.util.*;
public class HeapPollutionExample {
// ...
public static void main(String[] args) {
// ...
ArrayBuilder.addToList(listOfStringLists, stringListA, stringListB);
ArrayBuilder.addToList2(listOfStringLists, stringListA, stringListB);
ArrayBuilder.addToList3(listOfStringLists, stringListA, stringListB);
// ...
}
}
Java编译器为此示例生成以下警告:
Swing 的增强主要包含如下几点:
自定义WallpaperLayerUI装饰类继承LayerUI重写paint方法
import javax.swing.*;
import javax.swing.plaf.LayerUI;
import java.awt.*;
//继承 LayerUI 实现自定义装饰内容。
public class WallpaperLayerUI extends LayerUI<JComponent> {
@Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
Graphics2D g2 = (Graphics2D) g.create();
int w = c.getWidth();
int h = c.getHeight();
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, .5f));
//透明颜色渐变
g2.setPaint(new GradientPaint(0, 0, Color.yellow, 0, h, Color.red));
g2.fillRect(0, 0, w, h);
g2.dispose();
}
}
import javax.swing.*;
import javax.swing.plaf.LayerUI;
public class Test {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createUI();
}
});
}
public static void createUI() {
//创建JFrame
JFrame f = new JFrame("Wallpaper");
JPanel panel = createPanel();
// 这就是使用JDK7新特性:JLayer 类的装饰功能。如果不使用装饰 可以将 直接 f.add(panel)
LayerUI<JComponent> layerUI = new WallpaperLayerUI();
JLayer<JComponent> jlayer = new JLayer<JComponent>(panel, layerUI);
f.add (jlayer);
// f.add(panel);
//设置 JFrame 宽高 默认关闭 相对位置 和 可见。
f.setSize(300, 200);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo (null);
f.setVisible (true);
}
private static JPanel createPanel() {
//创建面板
JPanel p = new JPanel();
//创建一个按钮组,并添加 Beef、Chicken 和 Vegetable 三个单选按钮
ButtonGroup entreeGroup = new ButtonGroup();
JRadioButton radioButton;
p.add(radioButton = new JRadioButton("Beef", true));
entreeGroup.add(radioButton);
p.add(radioButton = new JRadioButton("Chicken"));
entreeGroup.add(radioButton);
p.add(radioButton = new JRadioButton("Vegetable"));
entreeGroup.add(radioButton);
//添加 Ketchup 、 Mustard 和 Pickles 复选框
p.add(new JCheckBox("Ketchup"));
p.add(new JCheckBox("Mustard"));
p.add(new JCheckBox("Pickles"));
//添加 Special requests: 标签 和 文本框
p.add(new JLabel("Special requests:"));
p.add(new JTextField(20));
//添加 Place Order 按钮
JButton orderButton = new JButton("Place Order");
p.add(orderButton);
return p;
}
}
https://www.oracle.com/technetwork/cn/java/javase/8-whats-new-2157071-zhs.html
Lambda 表达式是一个新的语言特性,已经在此版本中引入。该特性让您可以将功能视为方法参数,或者将代码视为数据。使用 Lambda 表达式,您可以更简洁地表示单方法接口(称为功能接口)的实例。
方法引用为已经具有名称的方法提供了易于理解的 lambda 表达式。
默认方法允许将新功能添加到库的接口中,并确保与为这些接口的旧版本编写的代码的二进制兼容性。
重复批注支持对同一个声明或类型的使用多次应用相同的批注类型。
类型批注支持在使用类型的任何地方应用批注,而不仅限于声明。与可插拔类型系统结合使用时,此特性可改进代码的类型检查。
改进类型推断。
方法参数反射。
新的 java.util.stream
包中的类提供了一个 Stream API,支持对元素流进行函数式操作。Stream API 集成在 Collections API 中,可以对集合进行批量操作,例如顺序或并行的 map-reduce 转换。
针对存在键冲突的 HashMap 的性能改进
紧凑 profile包含 Java SE 平台的预定义子集,并且支持不需要在小型设备上部署和运行整个平台的应用。
默认启用客户端 TLS 1.2
AccessController.doPrivileged
的新变体支持代码断言其权限的子集,而不会阻止完全遍历堆栈来检查其他权限
更强大的基于密码的加密算法
JSSE 服务器端支持 SSL/TLS 服务器名称指示 (SNI) 扩展
支持 AEAD 算法:SunJCE 提供程序得到了增强,支持 AES/GCM/NoPadding 密码实现以及 GCM 算法参数。而且 SunJSSE 提供程序也得到了增强,支持基于 AEAD 模式的密码套件。请参阅 Oracle 提供程序文档,JEP 115。
密钥库增强,包括新的域密钥库类型 java.security.DomainLoadStoreParameter
和为 keytool 实用程序新增的命令选项 -importpassword
SHA-224 消息摘要
增强了对 NSA Suite B 加密的支持
更好地支持高熵随机数生成
新增了 java.security.cert.PKIXRevocationChecker
类,用于配置 X.509 证书的撤销检查
适用于 Windows 的 64 位 PKCS11
Kerberos 5 重放缓存中新增了 rcache 类型
支持 Kerberos 5 协议转换和受限委派
默认禁用 Kerberos 5 弱加密类型
适用于 GSS-API/Kerberos 5 机制的未绑定 SASL
针对多个主机名称的 SASL 服务
JNI 桥接至 Mac OS X 上的原生 JGSS
SunJSSE 提供程序中支持更强大的临时 DH 密钥
JSSE 中支持服务器端加密套件首选项自定义
本版本中实施了新的 Modena 主题。有关更多信息,请参阅 xexperience.com 上的博客。
新的 SwingNode
类允许开发人员将 Swing 内容嵌入到 JavaFX 应用中。请参阅 SwingNode
javadoc 和将 Swing 内容嵌入 JavaFX 应用中。
新的 UI 控件包括 DatePicker
和 TreeTableView
控件。
javafx.print
程序包为 JavaFX Printing API 提供了公共类。有关更多信息,请参阅 javadoc。
3D 图形特性现在包括 3D 形状、摄像头、灯光、子场景、材料、挑选和抗锯齿。JavaFX 3D 图形库中新增了 Shape3D
(Box
、Cylinder
、MeshView
和 Sphere
子类)、SubScene
、Material
、PickResult
、LightBase
(AmbientLight
和 PointLight
子类)和 SceneAntialiasing
API 类。此版本中的 Camera
API 类也已更新。请参阅 javafx.scene.shape.Shape3D
、javafx.scene.SubScene
、javafx.scene.paint.Material
、javafx.scene.input.PickResult
和 javafx.scene.SceneAntialiasing
类的相关 javadoc 以及 JavaFX 3D 图形入门文档。
WebView
类包含新特性和改进。有关其他 HTML5 特性(包括 Web 套接字、Web 辅助进程和 Web 字体)的更多信息,请参阅 HTML5 支持的特性。
增强了文本支持,包括双向文本、复杂文本脚本(如泰语和印地语控件)以及文本节点中的多行多样式文本。
此版本添加了对 Hi-DPI 显示的支持。
CSS Styleable* 类已成为公共 API。有关更多信息,请参阅 Javafx.css
javadoc。
新的 ScheduledService
类允许自动重新启动服务。
JavaFX 现在可用于 ARM 平台。适用于 ARM 的 JDK 包含 JavaFX 的基础组件、图形组件和控制组件。
可通过 jjs
命令来调用 Nashorn 引擎。
java
命令用于启动 JavaFX 应用。
重新编写了 java
手册页。
可通过 jdeps
命令行工具来分析类文件。
Java Management Extensions (JMX) 支持远程访问诊断命令。
jarsigner
工具提供了一个选项用于请求获取时间戳机构 (TSA) 的签名时间戳。
javac
命令的 -parameters
选项可用于存储正式参数名称,并启用反射 API 来检索正式参数名称。
javac
命令现已正确实施了 Java 语言规范 (JLS) 第 15.21 节中的相等运算符的类型规则。
javac
工具现在支持检查 javadoc
注释的内容,从而避免在运行 javadoc
时生成的文件中产生各种问题,例如无效的 HTML 或可访问性问题。可通过新的 Xdoclint
选项来启用此特性。有关更多详细信息,请参阅运行“javac-X
”时的输出。此特性也可以在 javadoc
工具中使用,并且默认启用。
javac
工具现在支持根据需要生成原生标头。这样便无需在构建管道中单独运行 javah
工具。可以使用新的 -h
选项在 javac
中启用此特性,该选项用于指定写入头文件的目录。将为任何具有原生方法或者使用 java.lang.annotation.Native
类型的新批注的类进行批注的常量字段生成头文件。
javadoc
工具支持新的 DocTree
API,让您可以将 Javadoc 注释作为抽象语法树来进行遍历。
javadoc
工具支持新的 Javadoc Access API,让您可以直接从 Java 应用中调用 Javadoc 工具,而无需执行新的进程。有关更多信息,请参阅 javadoc 新特性页面。
javadoc
工具现在支持检查 javadoc
注释的内容,从而避免在运行 javadoc
时生成的文件中产生各种问题,例如无效的 HTML 或可访问性问题。此特性默认为启用状态,可以通过新的 -Xdoclint
选项加以控制。有关更多详细信息,请参阅运行“javadoc -X
”时的输出。javac
工具也支持此特性,但默认情况下并未启用它。
Unicode 增强,包括对 Unicode 6.2.0 的支持
采用 Unicode CLDR 数据和 java.locale.providers 系统属性
新增日历和区域设置 API
支持将自定义资源包作为扩展进行安装
现在可以使用 URLPermission
允许沙盒小程序和 Java Web Start 应用连接回启动它们的服务器。不再授予 SocketPermission
。
在所有安全级别,主 JAR 文件的 JAR 文件清单中都需要 Permissions 属性。
Date-Time 程序包 — 一组新程序包,提供全面的日期-时间模型。
Pack200 支持 JSR 292 引入的常量池条目和新字节码
JDK8 支持 JSR-292、JSR-308 和 JSR-335 指定的类文件更改
全新的基于 Solaris 事件端口机制的面向 Solaris 的 SelectorProvider
实现。要使用它,请将系统属性 java.nio.channels.spi.Selector
的值设置为 sun.nio.ch.EventPortSelectorProvider
。
减小 <JDK_HOME>/jre/lib/charsets.jar
文件的大小
提高了 java.lang.String(byte[], *)
构造函数和 java.lang.String.getBytes()
方法的性能。
并行数组排序
标准编码和解码 Base64
无符号算术支持
删除了 JDBC-ODBC Bridge。
JDBC 4.2 引入了新特性。
Java DB
已添加 java.net.URLPermission
类。
在 java.net.HttpURLConnection
类中,如果安装了安全管理器,那么请求打开连接的调用需要权限。
java.util.concurrent
程序包中新增了一些类和接口。
java.util.concurrent.ConcurrentHashMap
类中新增了一些方法,支持基于新增流工具和 lambda 表达式的聚合操作。
java.util.concurrent.atomic
程序包中新增了一些类来支持可扩展、可更新的变量。
java.util.concurrent.ForkJoinPool
类中新增了一些方法来支持通用池。
新增的 java.util.concurrent.locks.StampedLock
类提供了一个基于能力的锁,可通过三种模式来控制读/写访问。
新增的硬件内部函数以便使用高级加密标准 (AES)。UseAES
和 UseAESIntrinsics
标志用于为 Intel 硬件启用基于硬件的 AES 内部函数。硬件必须是 2010 年或更新的 Westmere 硬件。例如,要启用硬件 AES,请使用以下标志:
-XX:+UseAES -XX:+UseAESIntrinsics
要禁用硬件 AES,请使用以下标志:
-XX:-UseAES -XX:-UseAESIntrinsics
删除了 PermGen。
方法调用的字节码指令支持 Java 编程语言中的默认方法。
https://www.cnblogs.com/peter1018/p/9183548.html
Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
https://www.runoob.com/java/java8-lambda-expressions.html
方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
https://www.runoob.com/java/java8-method-references.html
https://www.runoob.com/java/java8-functional-interfaces.html
默认方法就是一个在接口里面有了一个实现的方法。
https://www.runoob.com/java/java8-default-methods.html
新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
https://www.runoob.com/java/java8-streams.html
加强对日期与时间的处理。
https://www.runoob.com/java/java8-datetime-api.html
Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
https://www.runoob.com/java/java8-optional-class.html
Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
https://www.runoob.com/java/java8-nashorn-javascript.html
在Java 8中,Base64编码已经成为Java类库的标准。
Java 8 内置了 Base64 编码的编码器和解码器。
Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:
https://www.runoob.com/java/java8-base64.html
https://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUID-C23AFD78-C777-460B-8ACE-58BE5EA681F6
http://www.oracle.com/technetwork/java/javase/9-relnotes-3622618.html
102: Process API Updates
110: HTTP 2 Client
143: Improve Contended Locking
158: Unified JVM Logging
165: Compiler Control
193: Variable Handles
197: Segmented Code Cache
199: Smart Java Compilation, Phase Two
200: The Modular JDK
201: Modular Source Code
211: Elide Deprecation Warnings on Import Statements
212: Resolve Lint and Doclint Warnings
213: Milling Project Coin
214: Remove GC Combinations Deprecated in JDK 8
215: Tiered Attribution for javac
216: Process Import Statements Correctly
217: Annotations Pipeline 2.0
219: Datagram Transport Layer Security (DTLS)
220: Modular Run-Time Images
221: Simplified Doclet API
222: jshell: The Java Shell (Read-Eval-Print Loop)
223: New Version-String Scheme
224: HTML5 Javadoc
225: Javadoc Search
226: UTF-8 Property Files
227: Unicode 7.0
228: Add More Diagnostic Commands
229: Create PKCS12 Keystores by Default
231: Remove Launch-Time JRE Version Selection
232: Improve Secure Application Performance
233: Generate Run-Time Compiler Tests Automatically
235: Test Class-File Attributes Generated by javac
236: Parser API for Nashorn
237: Linux/AArch64 Port
238: Multi-Release JAR Files
240: Remove the JVM TI hprof Agent
241: Remove the jhat Tool
243: Java-Level JVM Compiler Interface
244: TLS Application-Layer Protocol Negotiation Extension
245: Validate JVM Command-Line Flag Arguments
246: Leverage CPU Instructions for GHASH and RSA
247: Compile for Older Platform Versions
248: Make G1 the Default Garbage Collector
249: OCSP Stapling for TLS
250: Store Interned Strings in CDS Archives
251: Multi-Resolution Images
252: Use CLDR Locale Data by Default
253: Prepare JavaFX UI Controls & CSS APIs for Modularization
254: Compact Strings
255: Merge Selected Xerces 2.11.0 Updates into JAXP
256: BeanInfo Annotations
257: Update JavaFX/Media to Newer Version of GStreamer
258: HarfBuzz Font-Layout Engine
259: Stack-Walking API
260: Encapsulate Most Internal APIs
261: Module System
262: TIFF Image I/O
263: HiDPI Graphics on Windows and Linux
264: Platform Logging API and Service
265: Marlin Graphics Renderer
266: More Concurrency Updates
267: Unicode 8.0
268: XML Catalogs
269: Convenience Factory Methods for Collections
270: Reserved Stack Areas for Critical Sections
271: Unified GC Logging
272: Platform-Specific Desktop Features
273: DRBG-Based SecureRandom Implementations
274: Enhanced Method Handles
275: Modular Java Application Packaging
276: Dynamic Linking of Language-Defined Object Models
277: Enhanced Deprecation
278: Additional Tests for Humongous Objects in G1
279: Improve Test-Failure Troubleshooting
280: Indify String Concatenation
281: HotSpot C++ Unit-Test Framework
282: jlink: The Java Linker
283: Enable GTK 3 on Linux
284: New HotSpot Build System
285: Spin-Wait Hints
287: SHA-3 Hash Algorithms
288: Disable SHA-1 Certificates
289: Deprecate the Applet API
290: Filter Incoming Serialization Data
291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector
292: Implement Selected ECMAScript 6 Features in Nashorn
294: Linux/s390x Port
295: Ahead-of-Time Compilation
297: Unified arm32/arm64 Port
298: Remove Demos and Samples
299: Reorganize Documentation
模块是一个包的容器,Java 9 最大的变化之一是引入了模块系统(Jigsaw 项目)。
java9以前 :package => class/interface。
java9以后 :module => package => class/interface。
那么JDK被拆为了哪些模块呢?打开终端执行java --list-modules查看。
https://www.runoob.com/java/java9-module-system.html
https://zhuanlan.zhihu.com/p/31104953
交互式编程环境。
https://www.runoob.com/java/java9-repl.html
HTTP/2标准是HTTP协议的最新版本,新的 HTTPClient API 支持 WebSocket 和 HTTP2 流以及服务器推送特性。
Javadoc 现在支持在 API 文档中的进行搜索。另外,Javadoc 的输出现在符合兼容 HTML5 标准。支持搜索功能.
JDK8 生成的java帮助文档是在 HTML4 中。而HTML4 已经是很久的标准了。
JDK9 的javadoc,现支持HTML5 标准。
https://www.runoob.com/java/java9-improved-javadocs.html
多版本兼容 JAR 功能能让你创建仅在特定版本的 Java 环境中运行库程序时选择使用的 class 版本。
https://www.runoob.com/java/java9-multirelease-jar.html
List,Set 和 Map 接口中,新的静态工厂方法可以创建这些集合的不可变实例。
https://www.runoob.com/java/java9-collection-factory-methods.html
在接口中使用private私有方法。我们可以使用 private 访问修饰符在接口中编写私有方法。
https://www.runoob.com/java/java9-private-interface-methods.html
改进的 API 来控制和管理操作系统进程。引进 java.lang.ProcessHandle 及其嵌套接口 Info 来让开发者逃离时常因为要获取一个本地进程的 PID 而不得不使用本地代码的窘境。
https://www.runoob.com/java/java9-process-api-improvements.html
改进的 Stream API 添加了一些便利的方法,使流处理更容易,并使用收集器编写复杂的查询。
https://www.runoob.com/java/java9-stream-api-improvements.html
如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。
https://www.runoob.com/java/java9-try-with-resources-improvement.html
注解 @Deprecated 可以标记 Java API 状态,可以表示被标记的 API 将会被移除,或者已经破坏。
https://www.runoob.com/java/java9-enhanced-deprecated-annotation.html
匿名类可以使用钻石操作符(Diamond Operator)。
https://www.runoob.com/java/java9-inner-class-diamond-operator.html
java.util.Optional 添加了很多新的有用方法,Optional 可以直接转为 stream。
https://www.runoob.com/java/java9-optional-class-improvements.html
定义多分辨率图像API,开发者可以很容易的操作和展示不同分辨率的图像了。
https://www.runoob.com/java/java9-multiresolution-image_api.html
CompletableFuture 类的异步机制可以在 ProcessHandle.onExit 方法退出时执行操作。
https://www.runoob.com/java/java9-completablefuture-api-improvements.html
内置了一个轻量级的JSON API
Java 9中引入了新的响应式流 API 来支持 Java 9 中的响应式编程。
JIT(Just-in-time)编译器可以在运行时将热点编译成本地代码,速度很快。但是 Java 项目现在变得很大很复杂,因此 JIT 编译器需要花费较长时间才能热身完,而且有些 Java 方法还没法编译,性能方面也会下降。AoT 编译就是为了解决这些问题而生的。
在 JDK 9 中, AOT(JEP 295: Ahead-of-Time Compilation)作为实验特性被引入进来,开发者可以利用新的 jaotc 工具将重点代码转换成类似类库一样的文件。虽然仍处于试验阶段,但这个功能使得 Java应用在被虚拟机启动之前能够先将 Java 类编译为原生代码。此功能旨在改进小型和大型应用程序的启动时间,同时对峰值性能的影响很小。
但是 Java 技术供应商 Excelsior 的营销总监 Dmitry Leskov 担心 AoT 编译技术不够成熟,希望 Oracle 能够等到 Java 10时有个更稳定版本才发布。
日志是解决问题的唯一有效途径:曾经很难知道导致 JVM 性能问题和导致 JVM 崩溃的根本原因。不同的 JVM 日志的碎片化和日志选项(例如:JVM 组件对于日志使用的是不同的机制和规则),这使得 JVM 难以进行调试。
解决该问题最佳方法:对所有的 JVM 组件引入一个单一的系统,这些 JVM 组件支持细粒度的和易配置的 JVM 日志。
https://www.cnblogs.com/peter1018/p/9209951.html
http://cr.openjdk.java.net/~iris/se/10/latestSpec/
http://www.oracle.com/technetwork/java/javase/10-relnote-issues-4108729.html#NewFeature
286: Local-Variable Type Inference
296: Consolidate the JDK Forest into a Single Repository
304: Garbage-Collector Interface
307: Parallel Full GC for G1
310: Application Class-Data Sharing
312: Thread-Local Handshakes
313: Remove the Native-Header Generation Tool (javah)
314: Additional Unicode Language-Tag Extensions
316: Heap Allocation on Alternative Memory Devices
317: Experimental Java-Based JIT Compiler
319: Root Certificates
322: Time-Based Release Versioning
很多人抱怨Java是一种强类型,需要引入大量的样板代码。甚至在这些情况下,给定好变量名,通常很清楚发生了什么,明显类型声明往往被认为是不必要的。许多流行的编程语言都已经支持某种形式的局部变量类型推断:如C++ (auto), C# (var), Scala (var/val), Go (declaration with :=)等。
JDK10 可以使用var作为局部变量类型推断标识符,此符号仅适用于局部变量,增强for循环的索引,以及传统for循环的本地变量;它不能使用于方法形式参数,构造函数形式参数,方法返回类型,字段,catch形式参数或任何其他类型的变量声明。
标识符var不是关键字;相反,它是一个保留的类型名称。这意味着var用作变量,方法名或则包名称的代码不会受到影响;但var不能作为类或则接口的名字(但这样命名是比较罕见的,因为他违反了通常的命名约定,类和接口首字母应该大写)。
参考一下示例:
var str = "ABC"; //根据推断为 字符串类型
var l = 10L;//根据10L 推断long 类型
var flag = true;//根据 true推断 boolean 类型
var flag1 = 1;//这里会推断boolean类型。0表示false 非0表示true
var list = new ArrayList<String>(); // 推断 ArrayList<String>
var stream = list.stream(); // 推断 Stream<String>
反编译class文件:
String str = "ABC";
long l = 10L;
boolean flag = true;
int flag1 = true;
ArrayList<String> list = new ArrayList();
Stream<String> stream = list.stream();
从上面示例可以看出,当我们是用复杂的方法时,不需要特意去指定他的具体类型返回,可以使用var推断出正确的数据类型,这在编码中,可以大幅减少我们对方法返回值的探究。
为了简化和简化开发,将JDK多存储库合并到一个存储库中。多年来,JDK的完整代码已经被分解成多个存储库。在JDK9 中有八个仓库:root、corba、hotspot、jaxp、jaxws、jdk、langtools和nashorn。在JDK10中被合并为一个存储库。
虽然这种多存储库模型具有一些有点,但它也有许多缺点,并且在支持各种可取的源代码管理操作方面做得很差。特别是,不可能在相互依赖的变更存储库之间执行原子提交。例如,如果一个bug修复或RFE的代码现在同时跨越了jdk和hotspot 存储库,那么对于两个存储库来说,在托管这两个不同的存储库中,对两个存储库的更改是不可能实现的。跨多个存储库的变更是常见。
这不是让开发者用来控制垃圾回收的接口;而是一个在 JVM 源代码中的允许另外的垃圾回收器快速方便的集成的接口。
垃圾回收接口为HotSpot的GC代码提供更好的模块化;在不影响当前代码的基础情况下,将GC添加到HotSpot变的更简单;更容易从JDK构建中排除GC。实际添加或删除GC不是目标,这项工作将使HotSpot中GC算法的构建时间隔离取得进展,但它不是完全构建时间隔离的目标。
JDK10 通过并行Full GC,改善G1的延迟。G1垃圾收集器在JDK 9中是默认的。以前的默认值并行收集器中有一个并行的Full GC。为了尽量减少对使用GC用户的影响,G1的Full GC也应该并行。
G1垃圾收集器的设计目的是避免Full收集,但是当集合不能足够快地回收内存时,就会出现完全GC。目前对G1的Full GC的实现使用了单线程标记-清除-压缩算法。JDK10 使用并行化标记-清除-压缩算法,并使用Young和Mixed收集器相同的线程数量。线程的数量可以由-XX:ParallelGCThreads选项来控制,但是这也会影响用Young和Mixed收集器的线程数量。
为了提高启动和内存占用,扩展现有的类数据共享(CDS)特性,允许将应用程序类放置在共享档案中。
在不执行全局VM安全点的情况下对线程执行回调的方法。让它停止单个线程而不是全部线程。
JDK10 从JDK中移除了javah 工具。该工具已被JDK8 (JDK-7150368)中添加javac高级功能所取代。此功能提供了在编译java源代码时编写本机头文件的功能,从而无需使用单独的工具。
JDK10 改善 java.util.Locale 类和相关的 API 以实现额外 BCP 47 语言标签的 Unicode 扩展。尤其以下扩展支持:
为支持以上扩展,JDK10对以下API进行更改:
启用HotSpot VM以在用户指定的备用内存设备上分配Java对象堆。随着廉价的NV-DIMM内存的可用性,未来的系统可能配备了异构的内存架构。这种技术的一个例子是英特尔的3D XPoint。这样的体系结构,除了DRAM之外,还会有一种或多种类型的非DRAM内存,具有不同的特征。具有与DRAM具有相同语义的可选内存设备,包括原子操作的语义,因此可以在不改变现有应用程序代码的情况下使用DRAM代替DRAM。所有其他的内存结构,如代码堆、metaspace、线程堆栈等等,都将继续驻留在DRAM中。
参考以下使用案例:
启用基于Java的JIT编译器Graal,将其用作Linux / x64平台上的实验性JIT编译器。Graal是一个基于Java的JIT编译器,它是JDK 9中引入的Ahead-of-Time(AOT)编译器的基础。使它成为实验性JIT编译器是Project Metropolis的一项举措,它是下一步是研究JDK的基于Java的JIT的可行性。
使Graal可用作实验JIT编译器,从Linux / x64平台开始。Graal将使用JDK 9中引入的JVM编译器接口(JVMCI)。Graal已经在JDK中,因此将它作为实验JIT将主要用于测试和调试工作。要启用Graal作为JIT编译器,请在java命令行上使用以下选项:
-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
在JDK中提供一组默认的root 认证权威(CA)证书。在Oracle的Java SE根CA程序中开源root证书,以使OpenJDK构建对开发人员更有吸引力,并减少这些构建和Oracle JDK构建之间的差异。
cacerts密钥存储库是JDK的一部分,它的目的是包含一组root证书,这些root证书可以用来在各种安全协议中使用的证书链中建立信任。然而,JDK源代码中的cacerts密钥库目前是空的。因此,诸如TLS之类的关键安全组件在OpenJDK构建中不会默认工作。为了解决这个问题,用户必须配置和填充cacerts密钥库,并使用一组root证书来记录,例如, JDK 9 release notes。
在JEP 223 引入的版本字符串方案比以往有了显著的改进,但是,该方案并不适合未来,现在Java SE平台和JDK的新版本严格按照六个月的节奏发布。JEP 223方案的主要困难在于发行版的版本号对于其前身的重要性和兼容性进行了编码。然而,在基于时间发布模式中,这些品质并不是事先知道的。在发布的开发周期中,它们可能会发生变化,直到最终的功能被集成为止。因此发布的版本号也是未知的。
使用JEP 223的版本号语义,每个在JDK发布版上工作或者在其上构建或使用组件的人都必须先说明发布的发布日期,然后切换到说版本号,已知。维护库,框架和工具的开发人员必须准备好更改在每个JDK发布周期后期检查版本号的代码。这对所有参与者来说都很尴尬和混乱。
因此,这里提出的主要改变是重新编制版本号来编码,而不是编码的兼容性和重要性,而是按照发布周期的时间推移。这是更适合基于时间的发布模型,因为每个发布周期,因此每个发布的版本号,总是提前知道。
后续的版本格式为:[1-9][0-9]((.0).[1-9][0-9])
该格式可以是任意长度,但前四个被赋予特定含义,如:\(FEATURE.\)INTERIM.\(UPDATE.\)PATCH
版本号永远不会有零元素结尾。如果一个元素及其后的所有元素在逻辑上具有零值,那么它们全部被省略。
在严格六个月的发布模式下,版本号如下所示:
http://www.oracle.com/technetwork/java/javase/11-relnote-issues-5012449.html#NewFeature
181: Nest-Based Access Control
309: Dynamic Class-File Constants
315: Improve Aarch64 Intrinsics
318: Epsilon: A No-Op Garbage Collector
320: Remove the Java EE and CORBA Modules
321: HTTP Client (Standard)
323: Local-Variable Syntax for Lambda Parameters
324: Key Agreement with Curve25519 and Curve448
327: Unicode 10
328: Flight Recorder
329: ChaCha20 and Poly1305 Cryptographic Algorithms
330: Launch Single-File Source-Code Programs
331: Low-Overhead Heap Profiling
332: Transport Layer Security (TLS) 1.3
333: ZGC: A Scalable Low-Latency Garbage Collector
(Experimental)
335: Deprecate the Nashorn JavaScript Engine
336: Deprecate the Pack200 Tools and API
https://www.oracle.com/technetwork/java/javase/12-relnote-issues-5211422.html#NewFeature
189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)
230: Microbenchmark Suite
325: Switch Expressions (Preview)
334: JVM Constants API
340: One AArch64 Port, Not Two
341: Default CDS Archives
344: Abortable Mixed Collections for G1
346: Promptly Return Unused Committed Memory from G1
https://www.oracle.com/technetwork/java/javase/13-relnote-issues-5460548.html#NewFeature
350:Dynamic CDS Archives
351:ZGC: Uncommit Unused Memory
353:Reimplement the Legacy Socket API
354:Switch Expressions (Preview)
355:Text Blocks (Preview)
了解这个特性之前,需要先了解一下跟它有很大关联的特性JEP310:Application Class-Data Sharing,简称AppCDS。这个特性简介就是为了改善JVM应用的启动速度和内存占用,并且扩展了CDS(Class-Data Sharing)特性从而允许应用的类也可以被放置在共享的归档类(archived classes)文件中。这个JEP310的主要目标如下:
成功参考指标:
JEP350特性期望扩展CDS,从而允许在Java应用执行后进行动态类归档,归档的类将包括当前默认基础CDS归档中不存在的应用类和库中的类。这个特性的主要目标有:
在这之前,如果Java应用要使用CDS的话,3个步骤是必须的:
使用示例:
# JVM退出时动态创建共享归档文件
bin/java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello
# 用动态创建的共享归档文件运行应用
bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello
增强ZGC特性,将没有使用的堆内存归还给操作系统。ZGC当前不能把内存归还给操作系统,即使是那些很久都没有使用的内存,有点像貔貅一样,只进不出,哈哈。这种行为并不是对任何应用和环境都是友好的,尤其是那些内存占用敏感的服务,例如:
HotSpot的G1和Shenandoah这两个GC已经提供了这种能力,并且对某些用户来说,非常有用。因此,把这个特性引入ZGC会得到这些用户的欢迎。
ZGC的堆又若干个Region组成,每个Region被称之为ZPage。每个Zpage与数量可变的已提交内存相关联。当ZGC压缩堆的时候,ZPage就会释放,然后进入page cache,即ZPageCache。这些在page cache中的ZPage集合就表示没有使用部分的堆,这部分内存应该被归还给操作系统。回收内存可以简单的通过从page cache中逐出若干个选好的ZPage来实现,由于page cache是以LRU顺序保存ZPage的,并且按照尺寸(小,中,大)进行隔离,因此逐出ZPage机制和回收内存相对简单了很多,主要挑战是设计关于何时从page cache中逐出ZPage的策略。
一个简单的策略就是设定一个超时或者延迟值,表示ZPage被驱逐前,能在page cache中驻留多长时间。这个超时时间会有一个合理的默认值,也可以通过JVM参数覆盖它。Shenandoah GC用了一个类型的策略,默认超时时间是5分钟,可以通过参数-XX:ShenandoahUncommitDelay = milliseconds覆盖默认值。
像上面这样的策略可能会运作得相当好。但是,用户还可以设想更复杂的策略:不需要添加任何新的命令行选项。 例如,基于GC频率或某些其他数据找到合适超时值的启发式算法。JDK13将使用哪种具体策略目前尚未确定。可能最初只提供一个简单的超时策略,使用-XX:ZUncommitDelay = seconds选项,以后的版本会添加更复杂、更智能的策略(如果可以的话)。
uncommit能力默认是开启的,但是无论指定何种策略,ZGC都不能把堆内存降到低于Xms。这就意味着,如果Xmx和Xms相等的话,这个能力就失效了,-XX:-ZUncommit这个参数也能让这个内存管理能力失效。
用一个易于维护和Debug的,更简单、更现代的实现来取代java.net.Socket和java.net.ServerSocket。Socket和ServerSocket可以追溯到JDK1.0,它们的实现混合了Java和C代码,维护和调试都非常痛苦。而且其实现用线程栈来进行IO buffer,导致某些场景需要调大Xss。
全新实现的NioSocketImpl,用来取代PlainSocketImpl,它的优点如下:
扩展Switch表达式,既能用陈述的方式,也能用表达式的方式。并且这两种形式都可以用传统方式(case ... : labels),或者新的方式(case ... -> labels),并且还准备引入表达式匹配(JEP305),类似这种玩法:
if (obj instanceof String s && s.length() > 5) {
.. s.contains(..) ..
}
Switch表达式最初在JEP325中被提出,在JDK12中作为预览特性,根据反馈,这次的JEP354相比JEP325有一些改变,新版Switch表达式用法参考如下:
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
即文本块。文本块就是指多行字符串,例如一段格式化后的xml、json等。用户不需要转义,Java能自动搞定。这个需求是承接自JEP326,JEP326已经废弃。
JEP326使用`这个符号,例如:
String html = `<html>
<body>
<p>Hello World.</p>
</body>
</html>
`;
JEP355使用"""这个符号,例如:
String html = """
<html>
<body>
<p>Hello World.</p>
</body>
</html>
""";
JEP326废除的原因:
JEP326时把注意力放在字符串的原始性上,但是现在意识到这种关注是错误的。因为源码中原始字符串跨多行是很常见的,但是在内容中支付非转义分隔符的代码很大,这样的话,在用户使用多行字符串的时候,效率就会受到影响。原文如下:
because while raw string literals could easily span multiple lines of source code, the cost of supporting unescaped delimiters in their content was extreme. This limited the effectiveness of the feature in the multi-line use case
新版本文本块特性的目标:
接下来展示几种使用代码块特性前后的字符串申明方式。
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
二维表达方式(新):
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
"WHERE `CITY` = 'INDIANAPOLIS'\n" +
"ORDER BY `EMP_ID`, `LAST_NAME`;\n";
二维表达方式(新):
String query = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";
http://openjdk.java.net/projects/jdk/14/
305:Pattern Matching for instanceof (Preview)
343:Packaging Tool (Incubator)
345:NUMA-Aware Memory Allocation for G1
349:JFR Event Streaming
352:Non-Volatile Mapped Byte Buffers
358:Helpful NullPointerExceptions
359:Records (Preview)
361:Switch Expressions (Standard)
362:Deprecate the Solaris and SPARC Ports
363:Remove the Concurrent Mark Sweep (CMS) Garbage Collector
364:ZGC on macOS
365:ZGC on Windows
366:Deprecate the ParallelScavenge + SerialOld GC Combination
367:Remove the Pack200 Tools and API
368:Text Blocks (Second Preview)
370:Foreign-Memory Access API (Incubator)
http://openjdk.java.net/projects/jdk/15/
339:Edwards-Curve Digital Signature Algorithm (EdDSA)
360:Sealed Classes (Preview)
371:Hidden Classes
372:Remove the Nashorn JavaScript Engine
373:Reimplement the Legacy DatagramSocket API
374:Disable and Deprecate Biased Locking
375:Pattern Matching for instanceof (Second Preview)
377:ZGC: A Scalable Low-Latency Garbage Collector
378:Text Blocks
379:Shenandoah: A Low-Pause-Time Garbage Collector
381:Remove the Solaris and SPARC Ports
383:Foreign-Memory Access API (Second Incubator)
384:Records (Second Preview)
385:Deprecate RMI Activation for Removal
http://openjdk.java.net/projects/jdk/16/
338:Vector API (Incubator)
347:Enable C++14 Language Features
357:Migrate from Mercurial to Git
369:Migrate to GitHub
376:ZGC: Concurrent Thread-Stack Processing
380:Unix-Domain Socket Channels
386:Alpine Linux Port
387:Elastic Metaspace
388:Windows/AArch64 Port
389:Foreign Linker API (Incubator)
390:Warnings for Value-Based Classes
392:Packaging Tool
393:Foreign-Memory Access API (Third Incubator)
394:Pattern Matching for instanceof
395:Records
396:Strongly Encapsulate JDK Internals by Default
397:Sealed Classes (Second Preview)
http://openjdk.java.net/projects/jdk/17/
306:Restore Always-Strict Floating-Point Semantics
356:Enhanced Pseudo-Random Number Generators
382:New macOS Rendering Pipeline
391:macOS/AArch64 Port
398:Deprecate the Applet API for Removal
403:Strongly Encapsulate JDK Internals
406:Pattern Matching for switch (Preview)
407:Remove RMI Activation
409:Sealed Classes
410:Remove the Experimental AOT and JIT Compiler
411:Deprecate the Security Manager for Removal
412:Foreign Function & Memory API (Incubator)
414:Vector API (Second Incubator)
415:Context-Specific Deserialization Filters
https://openjdk.java.net/projects/jdk/18/
400: UTF-8 by Default
408: Simple Web Server
413: Code Snippets in Java API Documentation
416: Reimplement Core Reflection with Method Handles 2021/10/26
417: Vector API (Third Incubator)