Java程序员掉发系列——JDK各个版本的新特性详解

一、JDK1.5新特性:

1、自动装箱与拆箱:

  自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中。
  自动拆箱的过程:每当需要一个值时,被装箱对象中的值就被自动地提取出来,没必要再去调用intValue()和doubleValue()方法。
  自动装箱,只需将该值赋给一个类型包装器引用,java会自动创建一个对象。
  自动拆箱,只需将该对象值赋给一个基本类型即可。

java——类的包装器
类型包装器有:Double,Float,Long,Integer,Short,Character和Boolean

2、枚举

  把集合里的对象元素一个一个提取出来。枚举类型使代码更具可读性,理解清晰,易于维护。枚举类型是强类型的,从而保证了系统安全性。而以类的静态字段实现的类似替代模型,不具有枚举的简单性和类型安全性。

  简单的用法:JavaEnum简单的用法一般用于代表一组常用常量,可用来代表一类相同类型的常量值。

  复杂用法:Java为枚举类型提供了一些内置的方法,同事枚举常量还可以有自己的方法。可以很方便的遍历枚举对象。

3、静态导入

  通过使用 import static,就可以不用指定 Constants 类名而直接使用静态成员,包括静态方法。
import xxxx 和 import static xxxx的区别是前者一般导入的是类文件如import java.util.Scanner;后者一般是导入静态的方法,import static java.lang.System.out。

4、可变参数(Varargs)

  可变参数的简单语法格式为:methodName([argumentList], dataType…argumentName);

5、内省(Introspector)

  是Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其值或者设置新 的值。通过getName/setName来访问name属性,这就是默认的规则。Java中提供了一套API用来访问某个属性的getter /setter方法,通过这些API可以使你不需要了解这个规则(但你最好还是要搞清楚),这些API存放于包java.beans中。

  一 般的做法是通过类Introspector来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来 调用这些方法。

6、泛型(Generic)

  C++ 通过模板技术可以指定集合的元素类型,而Java在1.5之前一直没有相对应的功能。一个集合可以放任何类型的对象,相应地从集合里面拿对象的时候我们也 不得不对他们进行强制得类型转换。猛虎引入了泛型,它允许指定集合里元素的类型,这样你可以得到强类型在编译时刻进行类型检查的好处。

7、For-Each循环

  For-Each循环得加入简化了集合的遍历。假设我们要遍历一个集合对其中的元素进行一些处理。

8、JUC

  ConcurrentHashMap(简称CHM)是在Java 1.5作为Hashtable的替代选择新引入的,是concurrent包的重要成员。

二、JDK1.6新特性

1、Desktop类和SystemTray类

  在JDK6中,AWT新增加了两个类:Desktop和SystemTray。
前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档;后者可以用来在系统托盘区创建一个托盘程序.

2、使用JAXB2来实现对象与XML之间的映射

  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文档。除了JAXB之外,我们还可以通过XMLBeans和Castor等来实现同样的功能。

3、理解StAX

  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文档映射到一颗内存树,这样就可以很容易地得到父节点和子结点以及兄弟节点的数据,但如果文档很大,将会严重影响性能。

4、使用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提供了更加丰富的方式去做动态编译,而且是跨平台的。

5、轻量级Http Server API

  JDK6 提供了一个简单的Http Server API,据此我们可以构建自己的嵌入式Http Server,它支持Http和Https协议,提供了HTTP1.1的部分实现,没有被实现的那部分可以通过扩展已有的Http Server API来实现,程序员必须自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,在这里,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给 HttpHandler实现类的回调方法。

6、插入式注解处理API(Pluggable Annotation Processing API)

  插入式注解处理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来标识测试期间需要执行的测试方法。

7、用Console开发控制台程序

  JDK6 中提供了java.io.Console 类专用来访问基于字符的控制台设备。你的程序如果要与Windows下的cmd或者Linux下的Terminal交互,就可以用Console类代劳。但我们不总是能得到可用的Console, 一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用。如果JVM是在交互式命令行(比如Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实 例。

8、对脚本语言的支持如: ruby, groovy, javascript.

9、Common Annotations

  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 Annotation Retention Target Description

(1)Generated Source ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE 用于标注生成的源代码。

(2)Resource Runtime TYPE, METHOD, FIELD 用于标注所依赖的资源,容器据此注入外部资源依赖,有基于字段的注入和基于setter方法的注入两种方式。

(3)Resources Runtime TYPE 同时标注多个外部依赖,容器会把所有这些外部依赖注入。

(4)PostConstruct Runtime METHOD 标注当容器注入所有依赖之后运行的方法,用来进行依赖注入后的初始化工作,只有一个方法可以标注为PostConstruct。

(5)PreDestroy Runtime METHOD 当对象实例将要被从容器当中删掉之前,要执行的回调方法要标注为PreDestroy

(6)RunAs Runtime TYPE 用于标注用什么安全角色来执行被标注类的方法,这个安全角色必须和Container 的Security角色一致的。

(7)RolesAllowed Runtime TYPE, METHOD 用于标注允许执行被标注类或方法的安全角色,这个安全角色必须和Container 的Security角色一致的。

(8)PermitAll Runtime TYPE, METHOD 允许所有角色执行被标注的类或方法。

(9)DenyAll Runtime TYPE, METHOD 不允许任何角色执行被标注的类或方法,表明该类或方法不能在Java EE容器里面运行。

(10)DeclareRoles Runtime TYPE 用来定义可以被应用程序检验的安全角色,通常用isUserInRole来检验安全角色。

注意:
1、RolesAllowed,PermitAll,DenyAll不能同时应用到一个类或方法上;
2、标注在方法上的RolesAllowed,PermitAll,DenyAll会覆盖标注在类上的RolesAllowed,PermitAll,DenyAll;
3、RunAs,RolesAllowed,PermitAll,DenyAll和DeclareRoles还没有加到Java SE 6.0上来;
4、处理以上Annotations的工作是由Java EE容器来做, Java SE 6.0只是包含了上面表格的前五种Annotations的定义类,并没有包含处理这些Annotations的引擎,这个工作可以由Pluggable Annotation Processing API(JSR 269)来做。

  改动最大的地方就是java GUI界面的显示了,JDK6.0(也就是JDK1.6)支持最新的windows vista系统的Windows Aero视窗效果,而JDK1.5不支持!!!
  你要在vista环境下编程的话最好装jdk6.0,否则它总是换到windows basic视窗效果。

三、JDK1.7新特性

1、switch中可以使用字串了

String s = "test";
switch (s) {
	 case "test" :
	   System.out.println("test");
	 case "test1" :
	   System.out.println("test1");
	 break ;
	 default :
	  System.out.println("break");
	 break ;
}

2、"<>"这个玩意儿的运用List tempList = new ArrayList<>(); 即泛型实例化类型自动推断。

import java.util.*;
public class JDK7GenericTest {
   public static void main(String[] args) {
      // Pre-JDK 7
      List<String> lst1 = new ArrayList<String>();
      // JDK 7 supports limited type inference for generic instance creation
      List<String> lst2 = new ArrayList<>();
 
      lst1.add("Mon");
      lst1.add("Tue");
      lst2.add("Wed");
      lst2.add("Thu");
 
      for (String item: lst1) {
         System.out.println(item);
      }
 
      for (String item: lst2) {
         System.out.println(item);
      }
   }
}

3、自定义自动关闭类

  以下是jdk7 api中的接口,(不过注释太长,删掉了close()方法的一部分注释)

/**
 * A resource that must be closed when it is no longer needed.
 *
 * @author Josh Bloch
 * @since 1.7
 */
public interface AutoCloseable {
    /**
     * Closes this resource, relinquishing any underlying resources.
     * This method is invoked automatically on objects managed by the
     * {@code try}-with-resources statement.
     *
     */
    void close() throws Exception;
}

  只要实现该接口,在该类对象销毁时自动调用close方法,你可以在close方法关闭你想关闭的资源,例子如下

class TryClose implements AutoCloseable {

 @Override
 public void close() throw Exception {
  System.out.println(" Custom close method …
                                         close resources ");
 }
}
//请看jdk自带类BufferedReader如何实现close方法(当然还有很多类似类型的类)

  public void close() throws IOException {
        synchronized (lock) {
            if (in == null)
                return;
            in.close();
            in = null;
            cb = null;
        }
    }

4、 新增一些取环境信息的工具方法

File System.getJavaIoTempDir() // IO临时文件夹

File System.getJavaHomeDir() // JRE的安装目录

File System.getUserHomeDir() // 当前用户目录

File System.getUserDir() // 启动java进程时所在的目录

5、 Boolean类型反转,空指针安全,参与位运算

Boolean Booleans.negate(Boolean booleanObj)

True => False , False => True, Null => Null

boolean Booleans.and(boolean[] array)

boolean Booleans.or(boolean[] array)

boolean Booleans.xor(boolean[] array)

boolean Booleans.and(Boolean[] array)

boolean Booleans.or(Boolean[] array)

boolean Booleans.xor(Boolean[] array)

6、两个char间的equals

boolean Character.equalsIgnoreCase(char ch1, char ch2)

7、安全的加减乘除

int Math.safeToInt(long value)

int Math.safeNegate(int value)

long Math.safeSubtract(long value1, int value2)

long Math.safeSubtract(long value1, long value2)

int Math.safeMultiply(int value1, int value2)

long Math.safeMultiply(long value1, int value2)

long Math.safeMultiply(long value1, long value2)

long Math.safeNegate(long value)

int Math.safeAdd(int value1, int value2)

long Math.safeAdd(long value1, int value2)

long Math.safeAdd(long value1, long value2)

int Math.safeSubtract(int value1, int value2)

  对Java集合(Collections)的增强支持
在JDK1.7之前的版本中,Java集合容器中存取元素的形式如下:

1、以List、Set、Map集合容器为例:

//创建List接口对象
    List<String> list=new ArrayList<String>();
    list.add("item"); //用add()方法获取对象
    String Item=list.get(0); //用get()方法获取对象

 

    //创建Set接口对象
    Set<String> set=new HashSet<String>();
    set.add("item"); //用add()方法添加对象

 

    //创建Map接口对象
    Map<String,Integer> map=new HashMap<String,Integer>();
    map.put("key",1); //用put()方法添加对象
    int value=map.get("key");

2、在JDK1.7中,摒弃了Java集合接口的实现类,如:ArrayList、HashSet和HashMap。而是直接采用[]、{}的形式存入对象,采用[]的形式按照索引、键值来获取集合中的对象,如下:

 List<String> list=["item"]; //向List集合中添加元素
      String item=list[0]; //从List集合中获取元素

      Set<String> set={"item"}; //向Set集合对象中添加元素

      Map<String,Integer> map={"key":1}; //向Map集合中添加对象
      int value=map["key"]; //从Map集合中获取对象

3、数值可加下划线

例如:

int one_million = 1_000_000;

4.支持二进制文字

例如:

int binary = 0b1001_1001;

5、简化了可变参数方法的调用

  当程序员试图使用一个不可具体化的可变参数并调用一个varargs (可变)方法时,编辑器会生成一个“非安全操作”的警告。

6、在try catch异常扑捉中,一个catch可以写多个异常类型,用"|"隔开,

jdk7之前:

try {
   ......
} catch(ClassNotFoundException ex) {
   ex.printStackTrace();
} catch(SQLException ex) {
   ex.printStackTrace();
}

jdk7例子如下:

try {
   ......
} catch(ClassNotFoundException|SQLException ex) {
   ex.printStackTrace();
}

7、jdk7之前,你必须用try{}finally{}在try()内使用资源,在finally中关闭资源,不管try中的代码是否正常退出或者异常退出。jdk7之后,你可以不必要写finally语句来关闭资源,只要你在try()的括号内部定义要使用的资源。

  前提是try()内的那些资源要实现自定义自动关闭类,这是新特性 
try-with-resources statement。
请看例子:
jdk7之前:

import java.io.*;
// Copy from one file to another file character by character.
// Pre-JDK 7 requires you to close the resources using a finally block.
public class FileCopyPreJDK7 {
   public static void main(String[] args) {
      BufferedReader in = null;
      BufferedWriter out = null;
      try {
         in  = new BufferedReader(new FileReader("in.txt"));
         out = new BufferedWriter(new FileWriter("out.txt"));
         int charRead;
         while ((charRead = in.read()) != -1) {
            System.out.printf("%c ", (char)charRead);
            out.write(charRead);
         }
      } catch (IOException ex) {
         ex.printStackTrace();
      } finally {            // always close the streams
         try {
            if (in != null) in.close();
            if (out != null) out.close();
         } catch (IOException ex) {
            ex.printStackTrace();
         }
      }
 
      try {
         in.read();   // Trigger IOException: Stream closed
      } catch (IOException ex) {
         ex.printStackTrace();
      }
   }
}

jdk7之后:

import java.io.*;
// Copy from one file to another file character by character.
// JDK 7 has a try-with-resources statement, which ensures that
// each resource opened in try() is closed at the end of the statement.
public class FileCopyJDK7 {
   public static void main(String[] args) {
      try (BufferedReader in  = new BufferedReader(new FileReader("in.txt"));
           BufferedWriter out = new BufferedWriter(new FileWriter("out.txt"))) {
         int charRead;
         while ((charRead = in.read()) != -1) {
            System.out.printf("%c ", (char)charRead);
            out.write(charRead);
         }
      } catch (IOException ex) {
         ex.printStackTrace();
      }
   }
} 

JAVA7新增加了Objects类
  它提供了一些方法来操作对象,这些方法大多数是“空指针”安全的,比如 Objects.toString(obj);如果obj是null,则输出是null。
  否则如果你自己用obj.toString(),如果obj是null,则会抛出NullPointerException。

四、JDK1.8新特性

1、Lambda表达式

  Lambda表达式可以说是Java 8最大的卖点,它将函数式编程引入了Java。Lambda允许把函数作为一个方法的参数,或者把代码看成数据。
  一个Lambda表达式可以由用逗号分隔的参数列表、–>符号与函数体三部分表示。例如:

 Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e -> System.out.println( e ) ); 

  为了使现有函数更好的支持Lambda表达式,Java 8引入了函数式接口的概念。函数式接口就是只有一个方法的普通接口。java.lang.Runnable与java.util.concurrent.Callable是函数式接口最典型的例子。为此,Java 8增加了一种特殊的注解@FunctionalInterface:

@FunctionalInterface
public interface Functional {
    void method();
}

2、接口的默认方法与静态方法

  我们可以在接口中定义默认方法,使用default关键字,并提供默认的实现。所有实现这个接口的类都会接受默认方法的实现,除非子类提供的自己的实现。例如:

public interface DefaultFunctionInterface {
    default String defaultFunction() {
        return "default function";
    }
}

  我们还可以在接口中定义静态方法,使用static关键字,也可以提供实现。例如:

public interface StaticFunctionInterface {
    static String staticFunction() {
        return "static function";
    }
}

  接口的默认方法和静态方法的引入,其实可以认为引入了C++中抽象类的理念,以后我们再也不用在每个实现类中都写重复的代码了。

3、方法引用

  通常与Lambda表达式联合使用,可以直接引用已有Java类或对象的方法。一般有四种不同的方法引用:

    (1)构造器引用。语法是Class::new,或者更一般的Class< T >::new,要求构造器方法是没有参数;

    (2)静态方法引用。语法是Class::static_method,要求接受一个Class类型的参数;

    (3)特定类的任意对象方法引用。它的语法是Class::method。要求方法是没有参数的;

    (4)特定对象的方法引用,它的语法是instance::method。要求方法接受一个参数,与(3)不同的地方在于,(3)是在列表元素上分别调用方法,而(4)是在某个对象上调用方法,将列表元素作为参数传入;

4、重复注解

  在Java 5中使用注解有一个限制,即相同的注解在同一位置只能声明一次。Java 8引入重复注解,这样相同的注解在同一地方也可以声明多次。重复注解机制本身需要用@Repeatable注解。Java 8在编译器层做了优化,相同注解会以集合的方式保存,因此底层的原理并没有变化。

5、扩展注解的支持

  Java 8扩展了注解的上下文,几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,连方法的异常也能添加注解。

6、Optional

  Java 8引入Optional类来防止空指针异常,Optional类最先是由Google的Guava项目引入的。Optional类实际上是个容器:它可以保存类型T的值,或者保存null。使用Optional类我们就不用显式进行空指针检查了。

7、Stream

  Stream API是把真正的函数式编程风格引入到Java中。其实简单来说可以把Stream理解为MapReduce,当然Google的MapReduce的灵感也是来自函数式编程。她其实是一连串支持连续、并行聚集操作的元素。从语法上看,也很像linux的管道、或者链式编程,代码写起来简洁明了,非常酷帅!

8、Date/Time API (JSR 310)

  Java 8新的Date-Time API (JSR 310)受Joda-Time的影响,提供了新的java.time包,可以用来替代 java.util.Date和java.util.Calendar。一般会用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration这些类,对于时间日期的改进还是非常不错的。

9、JavaScript引擎Nashorn

  Nashorn允许在JVM上开发运行JavaScript应用,允许Java与JavaScript相互调用。

10、Base64

  在Java 8中,Base64编码成为了Java类库的标准。Base64类同时还提供了对URL、MIME友好的编码器与解码器。

除了这十大新特性之外,还有另外的一些新特性:

(1)更好的类型推测机制:Java 8在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。

(2)编译器优化:Java 8将方法的参数名加入了字节码中,这样在运行时通过反射就能获取到参数名,只需要在编译时使用-parameters参数。

(3)并行(parallel)数组:支持对数组进行并行处理,主要是parallelSort()方法,它可以在多核机器上极大提高数组排序的速度。

(4)并发(Concurrency):在新增Stream机制与Lambda的基础之上,加入了一些新方法来支持聚集操作。

(5)Nashorn引擎js:基于Nashorn引擎的命令行工具。它接受一些JavaScript源代码为参数,并且执行这些源代码。

(6)类依赖分析器jdeps:可以显示Java类的包级别或类级别的依赖。

(7)JVM的PermGen空间被移除:取代它的是Metaspace(JEP 122)。

另外Java8在JDK JUC 增加新的并发API

未完待续······

猜你喜欢

转载自blog.csdn.net/weixin_44563573/article/details/103338580
今日推荐