JDK各个版本的变化补充学习
JDK1.5
1. 类包装器.
自动装箱与拆箱。实际操作中比较常见。
2. 枚举类型使用。
实际中按需使用。我也在实际中使用过,需要注意的是使用枚举类型与扩展性的问题,比如性别永远只有”男”和”女”,不会增加扩展第三种,那么枚举是推荐使用的,如果枚举内容是扩展的,不建议使用枚举类型。
3. 静态方法倒入。
说实话,这个我在实际中真没有用过。语法import static
大致分两种:
(1)导入指定类的某个静态成员变量、方法。
(2)导入指定类的全部的静态成员变量、方法。
示例如下:
/*
* 使用import static,导入java.lang.System下的out这个静态成员变量
*/
import static java.lang.System.out;
public class ImptTest {
public static void main(String[] args) {
out.println("hello world");
}
}
导入静态方法示例:
/*
* 使用import static,导入java.lang.Math这个类中的round方法
*/
import static java.lang.Math.round;
public class ImptTest {
public static void main(String[] args) {
//out.println("hello world");
round(123.123);
}
}
导入全部静态成员、静态方法示例:
/*
* 像这样使用.*,则表示类中所有的静态成员变量和静态方法都被导入了
*/
import static java.lang.System.*;
import static java.lang.Math.*;
public class ImptTest {
public static void main(String[] args) {
out.println("hello world");
random();
}
}
4. 可变参数使用。
该特征在实际中使用过,实用性还是非常不错的。
主要特征:
(1)一个方法中只能指定一个可变参数,
(2)可变参数必须是方法的最后一个参数。
(3)可变参数类型必须一致.
(4)拥有可变参数的方法可以被重载,在调用方法的时,如果能够和固定参数的方法匹配,也能够与可变长参数的方法匹配,则会调用固定参数的方法。
(5)被调用的方法不允许和两个可变参数匹配,否则出现错误。
调用特点:
(1)可以不写参数,即传入空参。
(2)可以直接在里边写入参数,参数间用逗号隔开;
(3)可变参数兼容数组,数组不能兼容可变参数;
(4)注意参数里的null
如示例:
public static void say(String...names) {
for(String name : names) {
System.out.print(name + ",hello! ");
}
}
调用示例:
public static void main(String[] args) {
String[] names = {"tom", "cat", "dog"};
say(); // 不传递参数
say("dog", "cat"); // 传递多个参数
say(names); // 可传递数组
}
反面定义示例:
public static void say(String...names) {
for(String name : names) {
System.out.print(name + ",hello! ");
}
}
public static void say(String...names ,String...names) {
//不允许出现多个可变参数
}
public static void say(String sex, String...names) {
//调用时与第一个say方法冲突,不会被调用
}
public static void say(String...names,Sring date) {
//可变参数必须是最后一个参数
}
5. 内省(Introspector)
内省(Introspector) 是Java 语言对 JavaBean 类属性、事件的一种缺省处理方法。
JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object),或“VO”。方法比较少。这些信息储存在类的私有变量中,通过set()、get()获得。
实际使用引入apache的BeanUtils工具包:
BeanUtils工具包:下载:http://commons.apache.org/beanutils/
(应用的时候还需要一个logging包 http://commons.apache.org/logging/)
6.泛型(Generic).
简单的说就是可以指定集合里元素的类型。
7. for-each循环。
比较常用。语法for(类型 变量 : 集合){}
示例:
package com.zxc.jdk8;
public class ForEachTest {
public static void main(String[] args) throws JAXBException, IOException {
String[] names = {"tom","jerry","mike"};
for(String str : names){
System.out.println("str:"+str);
}
}
}
JDK1.6
主要变化
1、引入了一个支持脚本引擎的新框架Scripting for the Java Platform (JSR223脚本引擎)
2、UI的增强
3、对WebService支持的增强(JAX-WS2.0和JAXB2.0)
4、一系列新的安全相关的增强
5、JDBC4.0
6、Compiler API (JSR199)
支持动态编译。
public class JavaCompilerAPICompiler {
public void compile(Path src, Path output) throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(src.toFile());
Iterable<String> options = Arrays.asList("-d", output.toString());
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, compilationUnits);
boolean result = task.call();
}
}
}
7、通用的Annotations支持 (JSR269)
一部分是进行注解处理的javax.annotation.processing。
另一部分是对程序的静态结构进行建模的javax.lang.model。
JAXB2来实现对象与XML之间的映射
JAXB:
是Java Architecture for XML Binding的缩写,可以将一个Java对象和XML格式对象相互转换。JAXB2在底层是用StAX(JSR 173)来处理XML文档。
StAX(JSR 173)是JDK6.0中除了DOM和SAX之外的又一种处理XML文档的API。
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是The Streaming API for XML的缩写,一种利用拉模式解析(pull-parsing)XML文档的API.StAX通过提供一种基于事件迭代器(Iterator)的API让程序员去控制xml文档解析过程,程序遍历这个事件迭代器去处理每一个解析事件,解析事件可以看做是程序拉出来的,也就是程序促使解析器产生一个解析事件,然后处理该事件,之后又促使解析器产生下一个解析事件,如此循环直到碰到文档结束符;
SAX也是基于事件处理xml文档,但却是用推模式解析,解析器解析完整个xml文档后,才产生解析事件,然后推给程序去处理这些事件;DOM 采用的方式是将整个xml文档映射到一颗内存树,这样就可以很容易地得到父节点和子结点以及兄弟节点的数据,但如果文档很大,将会严重影响性能。
更多学习可以参考1:https://blog.csdn.net/visant/java/article/details/79778967
更多学习可以参考2:http://www.blogjava.net/hsith/archive/2006/06/29/55817.html
示例代码:
package com.zxc.jdk5;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Calendar;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Jaxb2Test {
public static void main(String[] args) throws JAXBException, IOException {
// TODO Auto-generated method stub
JAXBContext context = JAXBContext.newInstance(User.class);
//下面代码演示将对象转变为xml
Marshaller m = context.createMarshaller();
Address address = new Address("China","Shanghai","Shanghai"," xuhui","100080");
User user = new User("小菜",18,Calendar.getInstance(), address);
FileWriter fw = new FileWriter("D:\\user.xml");
m.marshal(user,fw);
//下面代码演示将上面生成的xml转换为对象
FileReader fr = new FileReader("D:\user.xml");
Unmarshaller um = context.createUnmarshaller();
User user2 = (User)um.unmarshal(fr);
System.out.println("Country:"+user2.getAddress().getCountry());//输入China
}
}
user类:
package com.zxc.jdk5;
import java.util.Calendar;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class User {
@XmlElement
String name;
@XmlElement
int age;
@XmlElement
Calendar birthDay;
@XmlElement
Address address;
public User() { }
public User(String name, int age, Calendar birthDay, Address address) {
super();
this.name = name;
this.age = age;
this.birthDay = birthDay;
this.address = address;
}
public Address getAddress() {
return address;
}
}
Address类
package com.zxc.jdk5;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
public class Address {
@XmlAttribute
String country;
@XmlElement
String province;
@XmlElement
String city;
@XmlElement
String street;
String houseNo; // 由于没有添加@XmlElement,所以该元素不会出现在输出的xml中
public Address() {}
public Address(String country, String province, String city, String street, String houseNo) {
super();
this.country = country;
this.province = province;
this.city = city;
this.street = street;
this.houseNo = houseNo;
}
public String getCountry() {
return country;
}
}
转换的XML内容:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user><name>小菜</name>
<age>18</age>
<birthDay>2020-02-24T22:09:03.019+08:00</birthDay>
<address country="China">
<province>Shanghai</province>
<city>Shanghai</city>
<street> xuhui</street>
</address>
</user>
注意@XmlAccessorType注解。
另Castor实现XML与Java的互转 http://www.castor.org/
另外还有 Compiler API,Http Server API,插入式注解处理API(Pluggable Annotation Processing API),对脚本语言的支持如: ruby, groovy, javascript,Common Annotations 涉及内容较多篇幅较长,后续单独学习。
JDK1.7
1. switch中可以使用字符串。
非常实用的。
2. 泛型实例化类型自动推断。
指定类型:
Map<String, String> myMap = new HashMap<String, String>();
自动推断:
Map<String, String> myMap = new HashMap<>();
3. 数值字面量改进.
数字前面加”0B”或”0b”表示二进制数。如:
int binary = 0b10011001;
数值中可以添加"_"
。 如:
int one_million = 1_000_000;
4. try-with-resources语句。
try-with-resources语句中会被自动调用,用于自动释放资源。自动关闭接口AutoCloseable。
try(OutputStream fos = new FileOutputStream("D:/file");){
// 不需要再次指明fos.close();
}
- 优化异常处理
try {
result = field.get(obj);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
JDK1.8
1. Lambda 表达式
Lambda表达式(也称为闭包)是整个Java 8发行版中最受期待的在Java语言层面上的改变,Lambda允许把函数作为一个方法的参数进行传递。
Lambda 表达式的标准格式:
(参数类型 参数名) -> {
方法体;
return 返回值;
}
Lambda 表达式的省略规则:
1. 小括号中的参数类型可以省略。
2. 如果小括号中只有一个参数,那么可以省略小括号。
3. 如果大括号中只有一条语句,那么可以省略大括号,return,分号。
其他注意:不允许声明一个与局部变量同名的参数或者局部变量。
四种方法引用类型
| 类型 | 示例 |
| 引用静态方法 | ContainingClass::staticMethodName |
| 引用某个对象的实例方法 |containingObject::instanceMethodName |
| 引用某个类型的任意对象的实例方法 | ContainingType::methodName |
| 引用构造方法 | ClassName::new |
// 使用 java 7 排序
private void sortJava7(List<String> names){
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
}
// 使用 java 8 排序
private void sortJava8(List<String> names){
Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
}
Lambda 使用条件
Lambda 表达式的使用前提:
必须有接口(不能是抽象类),接口中有且仅有一个需要被重写的抽象方法。
必须支持上下文推导,要能够推导出来 Lambda 表达式表示的是哪个接口中的内容。
可以使用接口当做参数,然后传递 Lambda 表达式(常用),也可以将 Lambda 表达式赋值给一个接口类型的变量。
package com.zxc.jdk8;
public interface MyInterface {
void printStr(String string);
}
public class LambdaTest {
//使用接口当做参数
public static void method(MyInterface m) {//m = s -> System.out.println(s)
m.printStr("hello world");
}
public static void main(String[] args) {
//使用接口当做参数,然后传递Lambda表达式。
//method(s -> System.out.println(s));
//使用匿名内部类方式创建对象
/*
MyInterface m = new MyInterface() {
@Override
public void printStr(String str) {
System.out.println(str);
}
};
*/
//Lambda 表达式赋值给接口类型变量
MyInterface m = str -> System.out.println(str);
m.printStr("hello world");
// 1.1使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello world !");
}
}).start();
// 1.2使用 lambda expression
new Thread(() -> System.out.println("Hello world !")).start();
// 2.1使用匿名内部类
Runnable race1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello world !");
}
};
// 2.2使用 lambda expression
Runnable race2 = () -> System.out.println("Hello world !");
// 直接调用 run 方法(没开新线程哦!)
race1.run();
race2.run();
}
}
2. 函数式接口
JDK 8之前就有的函数式接口(使用@FunctionalInterface定义 )
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
3. 接口默认方法与静态方法
接口默认方法,用default
关键字。
接口静态方法,用static
关键字:
package com.zxc.jdk8;
public interface MyInterface {
void printStr(String string);
default void log() {
System.out.println(" this is default method");
}
static boolean isNull(String str) {
System.out.println("Interface Null Check");
return str == null ? true : "".equals(str) ? true : false;
}
}
注意:类继承多个Interface接口同名方法(如show())时,必须在子类中@Override重写父类show()方法。
特性说明:
1,函数式接口仅仅只有一个方法(非默认或静态方法),用于显示转换成ladbma表达式。
2, java.lang.Runnable接口 java.util.concurrent.Callable接口是两个最典型的函数式接口。
3.如果一个函数式接口添加一个普通方法,就变成了非函数式接口(一般定义的接口)。
4.Jdk8 规范里添加了注解@FunctionalInterface来限制函数式接口不能修改为普通的接口.
jdk8新增了四个重要的函数式接口:函数形接口 、供给形接口、消费型接口、判断型接口
4. 日期时间的API.
新的时间及日期API类在java.time包中,不可变且线程安全的。
Instant获取时间戳, LocalDate只处理日期、LocalTime只处理时间,LocalDateTime只处理日期时间,ZonedDateTime包含时区的日期时间
TemporalAdjusters 日期调整
DateTimeFormatter 替代之前版本的SimpleDateFormat类
YearMonth年月组合,MonthDay月日组合
Clockdeng
package com.zxc.jdk8;
import java.time.Clock;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import static java.lang.System.out;
public class DateTimeTest {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now(Clock.systemUTC());
LocalDateTime dttm = LocalDateTime.now();
out.println(" date = " +date);
out.println(" time = " +time);
out.println(" dttm = " +dttm);
}
}
控制台输出:
date = 2020-05-31
time = 16:29:41.010
dttm = 2020-05-31T00:29:41.010
更多内容参考《java 查漏补缺-java8里的日期时间API》
5. Optional 类
Optional 是个容器,它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。比较友好的的解决空指针异常。Optional.of()或者Optional.ofNullable():创建Optional对象,差别在于of不允许参数是null,而ofNullable则无限制。
package com.zxc.jdk8;
import java.util.Optional;
import static java.lang.System.out;
public class OptionalTest {
public static void main(String[] args) {
// 参数不能是null
Optional<Integer> opt1 = Optional.of(1);
out.println(opt1);
// 参数可以是null
Optional<Integer> opt2 = Optional.ofNullable(null);
out.println(opt2);
// 参数可以是非null
Optional<Integer> opt3 = Optional.ofNullable(2);
Optional<String> opt4 = Optional.ofNullable("");
out.println(opt3);
out.println(opt4.isPresent());
// orElse
out.println(opt1.orElse(1000) == 1);// true
out.println(opt4.orElse("1000").equals("1000"));// true
out.println(optional1.orElseGet(() -> { return 1000;}) == 1);//true
}
}
6. Nashorn, JavaScript引擎。
Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
package com.zxc.jdk8;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class NashornTest {
public static void main(String[] args) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval("print('Hello World!');");
}
}
Nashorn JavaScript基于ECMAScript 5.1,但是它的后续版本会对ES6提供支持:
Nashorn的当前策略遵循ECMAScript规范。当我们在JDK8中发布它时,它将基于ECMAScript 5.1。Nashorn未来的主要发布基于ECMAScript 6。
Nashorn定义了大量对ECMAScript标准的语言和API扩展。但是首先让我们看一看Java和JavaScript代码如何交互。
注意:
该引擎在java11是被弃用。ECMAScript语言标准的快速发展,维护Nashorn引擎变得越发挑战,因此该引擎将在Java中废弃。
两个模块将会被最终弃用,被标注为@Deprecated(forRemoval=true)。
jdk.scripting.nashorn模块,包含dk.nashorn.api.scripting和jdk.nashorn.api.tree包。jdk.scripting.nashorn.shell模块,包含jjs工具,运行jjs将显示警告。
需要注意的是,java.scripting模块中javax.script包下的相关API不受影响。
7. 新工具
新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
Nashorn引擎jjs:
jjs是一个基于标准Nashorn引擎的命令行工具,可以接受js源码并执行。
类依赖分析器jdeps:
jdeps是一个命令行工具,它可以展示包层级和类层级的Java类依赖关系,它以.class文件、目录或者Jar文件为输入,然后会把依赖关系输出到控制台。
JVM的新特性
使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM参数方面,使用-XX:MetaSpaceSize
和-XX:MaxMetaspaceSize
代替原来的-XX:PermSize
和-XX:MaxPermSize
。
8. 其他
若遇到随时补充学习。