嘘~ 正在从服务器偷取页面 . . .

java 查漏补缺-jdk版本版本变化补充学习


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();
}
  1. 优化异常处理
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. 其他

若遇到随时补充学习。



版权声明: 本博客所有文章除特別声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明来源 Small-Rose / 张小菜 !
评论