JDK新特性

JDK1.6的九大新特性
一:Desktop类和SystemTray类
  在JDK1.6中,AWT新增加了两个类:Desktop和SystemTray。
  前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档;后者可以用来在系统托盘区创建一个托盘程序。
  二:使用JAXB2来实现对象与XML之间的映射
  JAXB是Java Architecture for XML Binding的缩写,可以将一个Java对象转变成为XML格式,反之亦然。
  我们把对象与关系数据库之间的映射称为ORM,其实也可以把对象与XML之间的映射称为OXM(Object XML Mapping)。原来JAXB是Java EE的一部分,在JDK1.6中,SUN将其放到了Java SE中,这也是SUN的一贯做法。JDK1.6中自带的这个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等来实现同样的功能。
  三:理解StAX
  StAX(JSR 173)是JDK1.6.0中除了DOM和SAX之外的又一种处理XML文档的API。
  StAX 的来历:在JAXP1.3(JSR 206)有两种处理XML文档的方法:DOM(Document Object Model)和SAX(Simple API for XML)。
  由于JDK1.6.0中的JAXB2(JSR 222)和JAX-WS 2.0(JSR 224)都会用到StAX所以Sun决定把StAX加入到JAXP家族当中来,并将JAXP的版本升级到1.4(JAXP1.4是JAXP1.3的维护版本)。JDK1.6里面JAXP的版本就是1.4。
  StAX是The Streaming API for XML的缩写,一种利用拉模式解析(pull-parsing)XML文档的API.StAX通过提供一种基于事件迭代器(Iterator)的API让程序员去控制xml文档解析过程,程序遍历这个事件迭代器去处理每一个解析事件,解析事件可以看做是程序拉出来的,也就是程序促使解析器产生一个解析事件然后处理该事件,之后又促使解析器产生下一个解析事件,如此循环直到碰到文档结束符;
  SAX也是基于事件处理xml文档,但却是用推模式解析,解析器解析完整个xml文档后,才产生解析事件,然后推给程序去处理这些事件;DOM采用的方式是将整个xml文档映射到一颗内存树,这样就可以很容易地得到父节点和子结点以及兄弟节点的数据,但如果文档很大,将会严重影响性能。
  四:使用Compiler API
  现在我 们可以用JDK1.6 的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提供了更加丰富的方式去做动态编译,而且是跨平台的。
  五:轻量级Http Server API
  JDK1.6 提供了一个简单的Http Server API,据此我们可以构建自己的嵌入式Http Server,它支持Http和Https协议,提供了HTTP1.1的部分实现,没有被实现的那部分可以通过扩展已有的Http Server API来实现,程序员必须自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,在这里,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给HttpHandler实现类的回调方法。
  六:插入式注解处理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来标识测试期间需要执行的测试方法。
  七:用Console开发控制台程序
  JDK1.6中提供了java.io.Console 类专用来访问基于字符的控制台设备。你的程序如果要与Windows下的cmd或者Linux下的Terminal交互,就可以用Console类代劳。但我们不总是能得到可用的Console,一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用。如果JVM是在交互式命令行(比如Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实例。
  八:对脚本语言的支持
  如: ruby,groovy,javascript。
  九: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 Generated Source ANNOTATION_TYPE,CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE 用于标注生成的源代码Resource Runtime TYPE,METHOD,FIELD用于标注所依赖的资源,容器据此注入外部资源依赖,有基于字段的注入和基于setter方法的注入两种方式 Resources Runtime TYPE同时标注多个外部依赖,容器会把所有这些外部依赖注入PostConstruct Runtime METHOD标注当容器注入所有依赖之后运行的方法,用来进行依赖注入后的初始化工作,只有一个方法可以标注为PostConstruct PreDestroy Runtime METHOD当对象实例将要被从容器当中删掉之前,要执行的回调方法要标注为PreDestroy RunAs Runtime TYPE用于标注用什么安全角色来执行被标注类的方法,这个安全角色必须和Container的Security角色一致的。RolesAllowed Runtime TYPE,METHOD用于标注允许执行被标注类或方法的安全角色,这个安全角色必须和Container的Security角色一致的 PermitAll Runtime TYPE,METHOD允许所有角色执行被标注的类或方法DenyAll Runtime TYPE,METHOD不允许任何角色执行被标注的类或方法,表明该类或方法不能在Java EE容器里面运行DeclareRoles Runtime TYPE用来定义可以被应用程序检验的安全角色,通常用isUserInRole来检验安全角色。
  注意:
  1.RolesAllowed,PermitAll,DenyAll不能同时应用到一个类或方法上标注在方法上的RolesAllowed,PermitAll,DenyAll会覆盖标注在类上的RolesAllowed,PermitAll,DenyAllRunAs,RolesAllowed,PermitAll,DenyAll和DeclareRoles还没有加到Java SE 6.0上来 处理以上Annotations的工作是由Java EE容器来做,Java SE 6.0只是包含了上面表格的前五种Annotations的定义类,并没有包含处理这些Annotations的引擎,这个工作可以由Pluggable Annotation Processing API(JSR 269)来做。

java SE 7规范(又名JDK 7)开发进展很顺利,计划于2011年夏天发布最终版本。为了让开发者能够方便快速地一览JDK 7中的所有重要元素,Developer.com发表了JDK 7 Reference Card,为开发者提供参考。

JSR203:JDK中会更多的IO API(“NIO.2”)
访问文件系统 与之前的JDK中通过java.io.File访问文件的方式不同,JDK7将通过java.nio.file包中的类完成。JDK7会使用java.nio.file.Path类来操作任何文件系统中的文件。(这里说的任何文件系统指的是可以使用任何文件存储方式的文件系统)
示例:

Java7之前

File file = new File(“some_file”);

使用Java7

Path path = Paths.get(“some_file”);

在File类中加入了新的方法toPath(),可以方便的转换File到Path

Path path = new File(“some_file”).toPath();

Socket通道绑定和配置 在JDK7中面向通道的网络编程也得以更新!JDK7中可以直接绑定通道的socket和直接操作socket属性。JDK7提供了平台socket属性和指定实现的socket属性。
JDK7加入了一个新的字节通道类,SeekableByteChannel
NetworkChannel是面向网络通道编程模块中的又一个新的超接口。利用它可以方便的绑定通道socket,并且方便设置和获取socket的属性。
MulticastChannel接口方便创建IP协议多播。多播实现直接绑定到本地的多播设备。
灵活的异步I/O 可以通过真正的异步I/O,在不同的线程中运行数以万计的流操作!JKD7提供了对文件和socket的异步操作。一些JDK7中的新通道:
AsynchronousFileChannel:异步文件通道可以完成对文件的异步读写操作。
AsynchronouseSocketChannel:Socket中的一个简单异步通道,方法是异步的并且支持超时。
AsynchronousServerSocketChannel:异步的ServerSocket
AsynchronousDatagramChannel:基于数据包的异步socket
JSR292:Java平台中的动态编程语言
Da Vinci Machine项目(JSR292)的主旨是扩展JVM支持除Java以外的其它编程语言,尤其是对动态编程语言的支持。所支持的语言必须和Java一样不收到歧视并共同存在。
JSR334:Java语言的一些改进
OpenJDK项目的创造(JSR334)的主旨是对Java语言进行一些小的改进来提高每天的Java开发人员的工作。这些改进包括:
Switch语句允许使用String类型
支持二进制常量和数字常量中可以使用下划线
使用一个catch语言来处理多种异常类型
对通用类型实例的创建提供类型推理
Try-with-resources语句来自动关闭资源
JSR119:Java编译器API
JSR199是在JDK6中加入的,主要用来提供调用Java编译器的API。除了提供javac的命令行工具,JSR199提供Java编译器到程序交互的能力。Java编译器API要达到三个目标:
对编译器和其它工具的调用
对结构化的编译信息进行访问
对文件输入输出定制化处理的能力
JSR206:Java XML处理的API (JAXP)
JSR206即Java API for XML Processing(JAXP),是Java处理XML文档的一个与实现无关,灵活的API。
JAXP1.3的主要特性包括:

DOM3
内建通过XML Schema进行文档校验的处理器
对XML Schema中的数据类型的实现,在javax.xml.datatype包中。
XSLTC,最快的转换器,也是XSLT处理中的默认引擎。
提供对XInclude的实现。这将会方便我们使用文本和其它已有的XML来创建新的文档,这样可以对文档片段进行重用。
JDK7中会包含JAXP1.3,这个是JAXP的最新实现。
绑定技术(JAXB)
JSR222即Java Architecture for XML Binding(JAXB)。JAXB的目的是便于Java程序进行Java类到XML文档的映射。
JAXB2的主要特性:

支持全部的W3C XML Schema特性。(JAXB1.0说明了对于W3C XML Schema中某些特性的不支持)
支持绑定Java到XML文档,通过添加javax.xml.bind.annotation包来控制绑定。
大量减少了对于schema衍生出来的类。
通过JAXP1.3的校验API来提供额外的校验能力。
JDK7中将包括JAXB2.2
JSR224:基于XML的Web服务API(JAX-WS)
JSR224即Java API for XML-based Web Services(JAX-WS),是一个基于Annotation标注的编程模型,主要针对Web Service应用和客户端开发。
JAX-WS2的主要特性包括:

对JAXB2.1 API的支持(JSR222)
对Web Services Addressing 1.0的支持
EndpointReference(EPR)的API:创建(BindingProvider.getEndpointReference(),Endpoint.getEndpointReference(),MessageContext.getEndpointReference())
事务处理(使用JAXB2.1绑定W3C EPR到W3CEndpointReference类,使用JAXB Marshall/Unmarshall W3CendpointReference类)

提供友好的API来启用和停止某些特性,例如MTOM特性和Addressing特性
JDK7将包含JAX-WS2.2
可插拔的Annotation处理API
JSR269即Pluggable Annotation-Processing API
从JDK5开始,Annotation标注就成了强大的机制用来标注我们的类、属性和方法。通常Annotation标注是在创建阶段或者运行阶段进行处理的,并获取语义结果。JSR269主要用来定义一套API,允许通过可插拔的API来进行标注处理器的创建。
规范包括一部分的API用来对Java编程语言进行构建,还有就对标注处理器声明和控制运行的部分。
有了程序中的Annotation标注,就需要有标注处理器框架来反射程序的结构。
Annotation处理器会指定他们处理的标注并且更多的处理器可以合作运行。
标注处理器和程序结构的API可以在构建阶段访问。
小的改进
java.util.Objects 提供了一套9个静态方法。其中两个方法用来检测当前对象是null还是非null。两个方法用来提供生成toString()字符串同时支持null对象。两个用来处理hash的方法。两个方法用来处理equals。最后一个compare方法用来进行比较。
Swing JLayer组件 JXLayer是一个组件装饰器,提供了用来装饰多个组合组件的方式,并且可以捕获所有鼠标、键盘和FocusEvent的事件,并针对所有的XLayer子组件。这个组件只会对public swing的api起作用,对全局设置没有作用,例如对EventQueue或者RepaintManager。(除了这些,Swing还将在JDK7中提供JXDatePicker和CSS方式样式)
并发和集合API JSR166,并发和集合API提供了灵活的异步处理,并发HashMap,传输队列和轻量级的fork/join框架以及本地线程方式的伪随机数生成器。
类加载器体系结构 类加载器已经升级到了可以在无等级类加载器拓扑中避免死锁。JDK7中包含了一个对于多线程自定义类加载器的增强实现,名字为具有并行能力的类加载器。使用平行能力的类加载器加载class,会同步到类加载器和类名。
Locale类的改进 Java Locale避免由于小的变化导致数据丢失。除此,Locale应该提供更多的特性,例如IETF BCP 47和UTR 35(CLDR/LDML)。
分离用户Locale和用户接口Locale JDK7分离了UI语言的locale和格式化locale,这个已经在Vista之后的windows系统中实现了。
严格的类文件检测 通过JavaSE6的规范,version51(SE7)的类文件和之后的版本必须通过类型检测来检验。对于老的推理验证VM不可以宕掉
Elliptic-Curve
Cryptography (ECC)椭圆曲线加密

从JDK7开始,Java提供对标准的ECC算法的灵活实现(基于椭圆曲线的公钥加密算法)
Swing中的Nimbus外观 Nimbus是JDS(Java Desktop System)中的新外观。这个也是Solaris11的GTK主题
Java2D中的XRender Pipeline JDK7中加入了基于X11 XRender扩展的Java2D图形管道。这将提供更多的对于当前先进的GPUs访问的功能。
TLS1.2 TLS (Transport Layer Security)是一个用在Internet上的数据传输安全协议,用来避免监听、引诱和消息伪造。TLS的主要目的是提供两个应用间通信的隐私和数据完整。TLS是RFC5246标准,在JDK7中提供1.2
JDBC4.0/4.1 JDBC4.1特性只在JDK7或者更高版本中存在。JDBC4.1只是对JDBC4.0进行较小的改动。关于一些JDBC4.0/4.1的特性:
数据源—Derby包括了对于javax.sql.DataSource的新的实现
JDBC驱动自动加载—应用不必在通过Class.forName()方法来加载数据库驱动了。取而代之的是DriverManager会根据应用请求连接的情况,自动查找到合适的JDBC驱动。
包装—这是JDBC4.0中的新的概念,主要是通过这种机制可以让应用获取的厂商提供的标准JDBC对象实现,例如Connections,Statements和ResultSets。
Statement事件—连接池可以监听Statement的关闭和错误时间。addStatementEventListener和removeStatementEventListener被加入到了javax.sql.PooledConnection
JDK7提供了JDBC4.1全部的支持
透明窗体和异形窗体 为了6u10版本的图形处理,JDK提供了透明效果的支持(简单透明和像素透明)并且提供了对于异形窗体的支持(可以将窗体设置成任意形状),轻重混合并且增强了AWT安全警告。透明效果和异形窗体是通过com.sun.awt.AWTUtilities类实现的。
Unicode6.0 Unicode6.0提供了诸如2.088字符集、对已经存在字符集的属性改进、格式化改进以及新的属性和数据文件。
JDK7已经更新到对Unicode6.0的支持。

要来关闭URLClassLoader的方法
对JMX代理和MBeans的改进

通过URLClassLoader,应用可以通过URL搜索路径来加载类和资源。JKD7提供了close()新方法来帮助URLClassLoader清理资源。
这个改进来至于JRockit,可以方便连接平台。MBean服务器可以通过防火墙提供一套MBeans,这些暴露了VM中的一些内部操作的信息

新的垃圾回收器 JDK7提供了新的垃圾回收器,针对目前的CMS垃圾回收器,这将会让垃圾回收器有更少的停顿时间和更高的语言效果。
改进的JSR
JSR901:Java Language Specification(JLS)Java语言计划
JSR901包括了从第一版Java规范到现在为止的所有的变化、说明和补充。Java语言通过JLS规范。
对于JLS的改变通过JSR901进行管理
JDK7将会包括最新的JSR901
JSR924:JVM平台规范
JSR924目的是维护Java虚拟机规范的变化,其中第二版是为了J2SE1.5的。
Java SE API
JavaSE APIs保持着对例行维护和小范围改进的加入计划的记录
延期到JDK8或者之后的规范
JSR294:Java语言和虚拟机对模块编程技术的支持—当前JSR主要的目的是提供在编译期和运行期的模块编程支持
JSR308:对于Java类型的Annotation注释—这将是对于当前注释符号系统的扩展,将允许我们在类型中出现注释符号。
JSR296:Swing应用框架—主旨是消除Swing编程中的模板代码并且提供Swing程序更加简单的结构。
模块化—提供一个明确的、简单的、低级别的模块系统,主要目的是将JDK模块化。
JSR TBD:Lambda项目—Lambda表达式(通俗的也称为“闭包“)和对Java编程语言的保护方法
JSR TBD:对于集合支持的语言—常量表达式对于lists、sets和maps的迭代以及通过索引符号对lists和maps的访问。
Swing JDatePicker组件—添加SwingLabs JXDatePicker组件到平台。

dk1.7新特性
1 对集合类的语言支持;
2 自动资源管理;
3 改进的通用实例创建类型推断;
4 数字字面量下划线支持;
5 switch中使用string;
6 二进制字面量;
7 简化可变参数方法调用;
8 新增一些取环境信息的工具方法;
9 Boolean类型反转,空指针安全,参与位运算;
10 两个char间的equals;
11 安全的加减乘除;
12 map集合支持并发请求 ,且可以写成 Map map = {name:"xxx",age:18};
   下面我们来仔细看一下这12个新功能:
      1 对集合类的语言支持
      Java将包含对创建集合类的第一类语言支持。这意味着集合类的创建可以像Ruby和Perl那样了。

创建List / Set / Map 时写法更简单了。
  List< String> list = ["item"]; 
String item = list[0]; 
Set< String > set = {"item"}; 
Map< String,Integer > map = {"key" : 1}; 
int value = map["key"];


      原本需要这样:
         List<String> list = new ArrayList<String>();
         list.add("item");
         String item = list.get(0);
  
         Set<String> set = new HashSet<String>();
         set.add("item");
         Map<String, Integer> map = new HashMap<String, Integer>();
         map.put("key", 1);
         int value = map.get("key");

      现在你可以这样:
         List<String> list = ["item"];
         String item = list[0];
        
         Set<String> set = {"item"};
        
         Map<String, Integer> map = {"key" : 1};
         int value = map["key"];

      这些集合是不可变的。

  
      2 自动资源管理
      Java中某些资源是需要手动关闭的,如InputStream,Writes,Sockets,Sql classes等。这个新的语言特性允许try语句本身申请更多的资源,
   这些资源作用于try代码块,并自动关闭。
      这个:
         BufferedReader br = new BufferedReader(new FileReader(path));
         try {
         return br.readLine();
               } finally {
                   br.close();
         }

      变成了这个:
          try (BufferedReader br = new BufferedReader(new FileReader(path)) {
             return br.readLine();
          }
   
      你可以定义关闭多个资源:
         try (
             InputStream in = new FileInputStream(src);
             OutputStream out = new FileOutputStream(dest))
         {
         // code
         }
      为了支持这个行为,所有可关闭的类将被修改为可以实现一个Closable(可关闭的)接口。
  

      3 增强的对通用实例创建(diamond)的类型推断
      类型推断是一个特殊的烦恼,下面的代码:
         Map<String, List<String>> anagrams = new HashMap<String, List<String>>();

      通过类型推断后变成:
         Map<String, List<String>> anagrams = new HashMap<>();
      这个<>被叫做diamond(钻石)运算符,这个运算符从引用的声明中推断类型。

  
      4 数字字面量下划线支持
      很长的数字可读性不好,在Java 7中可以使用下划线分隔长int以及long了,如:
         int one_million = 1_000_000;
   运算时先去除下划线,如:1_1 * 10 = 110,120 – 1_0 = 110
  

      5 switch中使用string
      以前你在switch中只能使用number或enum。现在你可以使用string了:
         String s = ...
         switch(s) {
         case "quux":
              processQuux(s);
     // fall-through
         case "foo":
   case "bar":
              processFooOrBar(s);
     break;
         case "baz":
        processBaz(s);
              // fall-through
   default:
              processDefault(s);
            break;
  }

 
      6 二进制字面量
      由于继承C语言,Java代码在传统上迫使程序员只能使用十进制,八进制或十六进制来表示数(numbers)。
      由于很少的域是以bit导向的,这种限制可能导致错误。你现在可以使用0b前缀创建二进制字面量:
         int binary = 0b1001_1001;
   现在,你可以使用二进制字面量这种表示方式,并且使用非常简短的代码,可将二进制字符转换为数据类型,如在byte或short。
   byte aByte = (byte)0b001;   
   short aShort = (short)0b010;   

  
      7 简化的可变参数调用
      当程序员试图使用一个不可具体化的可变参数并调用一个*varargs* (可变)方法时,编辑器会生成一个“非安全操作”的警告。
   JDK 7将警告从call转移到了方法声明(methord declaration)的过程中。这样API设计者就可以使用vararg,因为警告的数量大大减少了。

    8  新增一些取环境信息的工具方法
File System.getJavaIoTempDir()  // IO临时文件夹   
File System.getJavaHomeDir() // JRE的安装目录   
File System.getUserHomeDir() // 当前用户目录   
File System.getUserDir() // 启动java进程时所在的目录   
   9 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)
10 两个char间的equals

boolean  Character.equalsIgnoreCase( char  ch1,  char  ch2)  

11 安全的加减乘除

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)

12 map集合支持并发请求 ,且可以写成 Map map = {name:"xxx",age:18};

jdk1.5新特性介绍

泛型(Generics)--为集合(collections)提供编译时类型安全,无需每刻从Collections取得一个对象就进行强制转换(cast)

增强的“for”循环(Enhanced For loop)--减少迭代器(iterator)的潜在错误(error-proneness)

自动置入/自动取出(Autoboxing/unboxing)--无需在基本类型(primitive types)(例如double)和包装类型(wrapper types)(例如Double)之间人工地进行转换。

类型安全的枚举(Typesafeenums)--提供类型安全枚举模式的各项好处。

静态导入(Static import)--无需在使用其他类的静态成员变量前缀其类名.这将使得代码更为简洁。

元数据(Metadata)--使编程人员避免编写样板化代码(boiler plate code),并提供机会进行宣告式程式设计(declarative programming)。

  让我们详细讨论每个新特性,并看一些例子。

1、泛型(Generics)

  泛型是JDK1.5中一个最“酷”的特征。通过引入泛型,我们将获得编译时类型的安全和运行时更小地抛出ClassCastExceptions的可能。在JDK1.5中,你可以声明一个集合将接收/返回的对象的类型。在JDK1.4中,创建雇员名字的清单(List)需要一个集合对象,像下面的语句:

  List listOfEmployeeName = new ArrayList();

  在JDK1.5中,你将使用下面语句

  List<String> listOfEmployeeName = new ArrayList<String>();

  最“酷”的是,如果你试图插入非string类型的值,你将在编译时发现并且修正这类问题。没有泛型,你会发现这样一个bug,当你的客户调用后会告诉你,你所编写的程序抛出ClassCastException异常而崩溃。

  另外,当你从集合中得到一个元素时你无需进行强制转换。故原先为:

  String employeeName = ((String) listOfEmployee.get(i));

  而下面的语句将比上面的更加简单:

  String employeeName = listOfEmployee.get(i);

  不清楚对象的类型而强制转换对象是不合理的,并且更重要的是,它将在运行时失败。假使用户无意间传入一个包含string buffers类型而非string类型的集合,那结果会怎样呢。在Listing A中,客户被要求传入一个编译器无法强制的strings类型集合。Listing B中显示了同样的方法使用泛型是如何实现的。

  Listing A

  staticbooleancheckName(Collection employeeNameList, String name) {

  for (Iteratori = employeeNamList.iterator(); i.hasNext(); ) {

  String s = (String) i.next();

  if(s.equals(name)){

  return true;

  //print employee name here ......

  }

  }

  return false;

  }

  Listing B

  staticbooleancheckName(Collection<String> employeeNameList, String name) {

  for (Iteratori = employeeNamList.iterator(); i.hasNext(); ) {

  if(i.next().equals(name)){

  return true;

  //print employee name here ......

  }

  }

  return false;

  }

  现在,通过方法签名可以清楚知道输入集合必须只能包含strings。如果客户试图传入一个包含string buffers的集合,程序将不会编译。同时注意,该方法不包含任何强制转换。它只需要短短一行,一旦你习惯泛型后,它也更加清晰。

2、在JDK当前版本下的For循环语法如下:

  void printAll(Collection c) {

  for (Iteratori = c.iterator(); i.hasNext(); ) {

  Employee emp = (Employee)i.next();

  System.out.println(emp.getName());

  }

  }

  现在,用增强的For语句实现相同方法:

  voidprintAll(Collection c) {

  for (Object o : c)

  System.out.println((TimerTask)o).getName());

  }

  在这类For循环中,你应该将":"看成"in",所以,在该例中可以看成"for Object o in c"。你可以发现这种For循环更具可读性。

3、自动置入/自动取出(Autoboxing/unboxing)

  Java有基本数据类型,在这些基本数据类型周围又有包装类。通常,编程人员需要将一种类型转换成另一种。看看Listing C.中的代码片断。

  Listing C

  public class Employee {

  private static final Integer CHILD = new Integer(0);

  public static void main(String args[]) {

  //code for adding n to an Integer

  int n=10;

  Integer age= new Integer(30);

  Integer ageAfterTenYear= new Integer(age.intValue +10);

  }

  }

  请注意,用于计算ageAfterTenYear的内循环代码看上去是多么杂乱。现在,在Listing D.中看看相同的程序使用autoboxing重写后的样子。

  Listing D

  public class Employee {

  public static void main(String args[]) {

  int n=10;

  Integer age= new Integer(30);

  Integer ageAfterTenYear= age +10;

  }

  }

  有一件事值得注意的:在先前,如果你取出(unbox)Null值,它将变为0。在次代码中,编译器将自动地转换Integer为int然后加上10,接着将其转换回Integer.。

4、类型安全的枚举(Typesafeenums)

  类型安全枚举提供下列特性:

  他们提供编译时类型安全。

  他们都是对象,因此你不需要将他们放入集合中。

  他们作为一种类的实现,因此你可以添加一些方法。

  他们为枚举类型提供了合适的命名空间。

  他们打印的值具有情报性(informative)― 如果你打印一个整数枚举(intenum),你只是看见一个数字,它可能并不具有情报性。

  例一:

  enum Season { winter, spring, summer, fall }

  例二:

  public enum Coin {

  penny(1), nickel(5), dime(10), quarter(25);

  Coin(int value) { this.value = value; }

  private final int value;

  public int value() { return value; }

  }

5、静态导入(Static import)

  静态导入使代码更易读。通常,你要使用定义在另一个类中的常量(constants),像这样:

  importorg.yyy.pkg.Increment;

  class Employee {

  public Double calculateSalary(Double salary{

  return salary + Increment.INCREMENT * salary;

  }

  }

  当时使用静态导入,我们无需为常量名前缀类名就能使用这些常量,像这样:

  import static org.yyy.pkg.Increment;

  class Employee {

  public Double calculateSalary(Double salary{

  return salary + INCREMENT * salary;

  }

  }

  注意,我们可以调用INCREMENT这一常量而不要使用类名Increment.。

6、元数据(Metadata)

  元数据特征志于使开发者们借助厂商提供的工具可以进行更简易的开发。看一看Listing E.中的代码。

  Listing E

  importorg.yyy.hr;

  public interface EmployeeI extends Java.rmi.Remote {

  public String getName()

  throwsJava.rmi.RemoteException;

  public String getLocation ()

  throwsJava.rmi.RemoteException;

  }

  public class EmployeeImpl implements EmployeeI {

  public String getName(){

  }

  public String getLocation (){

  }

  }

  通过元数据的支持,你可以改写Listing E中的代码为:

  importorg.yyy.hr;

  public class Employee {

  @Remote public String getName() {

  ...

  }

  @Remote public public String getLocation() {

  ...

  }

  }


JDK1.5新特性之Java Generics

在JDK1.5之前的版本中,对于一个Collection类库中的容器类实例,可将任意类型

对象加入其中(都被当作Object实例看待);从容器中取出的对象也只是一个Object实例,需要将其强制转型为期待的类型,这种强制转型的运行时正确性由程序员自行保证。

例如以下代码片断:

List intList = new ArrayList(); //创建一个List,准备存放一些Integer实例
intList.add(new Integer(0));
intList.add(“1”); //不小心加入了一个字符串;但在编译和运行时都不报错,只有仔细的代码走
                       //才能揪出
Integer i0 = (Integer)intList.get(0);
Integer i1 = (Integer)intList.get(1); //编译通过,直到运行时才抛ClassCastException

而在JDK1.5中,可以创建一个明确只能存放某种特定类型对象的容器类实例,例如如下代码:
List<Integer> intList = new ArrayList<Integer>(); //intList为存放Integer实例的List
intList.add(new Integer(0));
Integer i0 = intList.get(0); //无需(Integer)强制转型;List<Integer>的get()返回的就是Integer类
                                    //型对象
intList.add(“1”); //编译不通过,因为List<Integer>的add()方法只接受Integer类型的参数

       “List<Integer> intList = new ArrayList<Integer>();”就是最简单且最常用的Generic应用;显然,运用Generic后的代码更具可读性和健壮性。

2         Generic类
JDK1.5中Collection类库的大部分类都被改进为Generic类。以下是从JDK1.5源码中

截取的关于List和Iterator接口定义的代码片断:

public interface List<E> {
       void add(E x);
       Iterator<E> iterator;
}

public interface Iterator<E> {
       E next();
       boolean hasNext();
}

以List为例,“public interface List<E>”中的E是List的类型参数,用户在使用List

时可为类型参数指定一个确定类型值(如List<Integer>)。类型值为Java编译器所用,确保用户代码类型安全。例如,编译器知道List<Integer>的add()方法只接受Integer类型的参数,因此如果你在代码中将一个字符串传入add()将导致编译错误;编译器知道Iterator<Integer>的next()方法返回一个Integer的实例,你在代码中也就无需对返回结果进行(Integer)强制转型。代码检验通过(语法正确且不会导致运行时类型安全问题)后,编译器对现有代码有一个转换工作。简单的说,就是去除代码中的类型值信息,在必要处添加转型代码。例如如下代码:

public String demo() {

       List<String> strList = new ArrayList<String>();

       strList.add(“Hello!”);

       return strList.get(0);

}

编译器在检验通过后,将其转换为:

public String demo() {

       List strList = new ArrayList(); //去除类型值<String>

       strList.add(“Hello!”);

       return (String)strList.get(0);  //添加转型动作代码(String)

}


       可见,类型值信息只为Java编译器在编译时所用,确保代码无类型安全问题;验证通过之后,即被去除。对于JVM而言,只有如JDK1.5之前版本一样的List,并无List<Integer>和List<String>之分。这也就是Java Generics实现中关键技术Erasure的基本思想。以下代码在控制台输出的就是“true”。

List<String> strList = new ArrayList<String>();

List<Integer> intList = new ArrayList<Integer>();

System.out.println(strList.getClass() == intList.getClass());


       可以将Generic理解为:为提高Java代码类型安全性(在编译时确保,而非等到运行时才暴露),Java代码与Java编译器之间新增的一种约定规范。Java编译器在编译结果*.class文件中供JVM读取的部分里没有保留Generic的任何信息;JVM看不到Generic的存在。

       对于Generic类(设为GenericClass)的类型参数(设为T):

1)        由于对于JVM而言,只有一个GenericClass类,所以GenericClass类的静态字段和静态方法的定义中不能使用T。T只能出现在GenericClass的非静态字段或非静态方法中。也即T是与GenericClass的实例相关的信息;

2)        T只在编译时被编译器理解,因此也就不能与运行时被JVM理解并执行其代表的操作的操作符(如instanceof 和new)联用。


class GenericClass<T> {

    T t1;

    public void method1(T t){

       t1 = new T(); //编译错误,T不能与new联用

       if (t1 instanceof T) {}; //编译错误,T不能与instanceof联用

    };

    static T t2; //编译错误,静态字段不能使用T

    public static void method2(T t){};//编译错误,静态方法不能使用T

}

       Generic类可以有多个类型参数,且类型参数命名一般为大写单字符。例如Collection类库中的Map声明为:

public interface Map<K,V> {

       ……;

}

3         Generic类和原(Raw)类
对每一个Generic类,用户在使用时可以不指定类型参数。例如,对于List<E>,用户

可以以“List<String> list;”方式使用,也可以以“List list;”方式使用。“List<String>”被称为参数化的Generic类(类型参数被赋值),而“List”称为原类。原类List的使用方式和效果与JDK1.5之前版本List的一样;使用原类也就失去了Generic带来的可读性和健壮性的增强。

       允许原类使用方式的存在显然是为了代码的向前兼容:即JDK1.5之前的代码在JDK1.5下仍然编译通过且正常运行。

       当你在JDK1.5中使用原类并向原类实例中添加对象时,编译器会产生警告,因为它无法保证待添加对象类型的正确性。编译通过是为了保证代码向前兼容,产生警告是提醒潜在的风险。

public void test () {

    List list = new ArrayList();

    list.add("tt");//JDK1.5编译器对此行产生警告

}

4 Generic类和子类
List<String> ls = new ArrayList<String>();

List<Object> lo = ls; //编译错误:Type mismatch: cannot convert from List<Dummy> to
                                                           //List<Object>

以上第二行代码导致的编译错误“Type mismatch: cannot convert from List<Dummy> to

List<Object>”是不是有点出人意料?直观上看,就像String是Object的子类,因此‘Object o = “String”’合法一样,存放String的List是存放Object的List的子类,因此第二行应该是合法的。反过来分析,如果第二行是合法的,那么如下会导致运行时异常的代码也是合法的:

lo.add(new Object); //会导致在ls中添加了非String对象

String s = ls.get(0); //ls.get(0)返回的实际上只是一个Object实例,会导致ClassCastException

       编译器显然不允许此种情形发生,因此不允许“List<Object> lo = ls”编译通过。

       因此,直观上的“存放String的List是存放Object的List的子类”是错误的。更一般的说,设Foo是Bar的子类,G是Generic类型声明,G<Foo>不是G<Bar>的子类。

5 参数化的Generic类和数组
我们知道,如果T是S的子类,则T[]也是S[]的子类。因此,如下代码编译通过,只

在运行时于第三行代码处抛ArrayStoreException。

String[] words = new String[10];

Object[] objects = words;

Objects[0] = new Object(); //编译通过,但运行时会抛ArrayStoreException


再分析如下代码:

List<String>[] wordLists = new ArrayList<String>[10];

ArrayList<Integer> integerList = new ArrayList<Integer>();

integerList.add(123);

Object[] objects = wordLists;

objects[0] = integerList;//运行时不出错,因为运行时ArrayList<String>和ArrayList<Integer>都
                                 //为ArrayList

String s = wordlists[0].get(0); //编译通过,运行时抛ClassCastException

       就出现了“正确使用了Generic,但在运行时仍然出现ClassCastException”的情形。显然Java编译器不允许此种情形的发生。事实上,以上代码的第一行“List<String>[] wordLists = new ArrayList<String>[10];”就是编译不通过的,也就不存在接下来的代码。

更一般地说,不能创建参数化的Generic类的数组。

6 类型参数通配符?
由“Generic类和子类”节知,Collection<Object>不是存放其它类型对象的Collection(例

如Collection<String>)的基类(抽象),那么如何表示任一种参数化的Collection的呢?使用Collection<?>。?即代表任一类型参数值。例如,我们可以很容易写出下面的通用函数printCollection():

public static void printCollection(Collection<?> c) {

    //如此遍历Collection的简洁方式也是JDK1.5新引入的

       for (Object o : c) {

              System.out.println(o);

    }

}

       这样,既可以将Collection<String>的实例,也可以将Collection<Integer>的实例作为参数调用printCollection()方法。

       然而,要注意一点,你不能往Collection<?>容器实例中加入任何非null元素,例如如下代码的第三行编译不通过:

public static void testAdd(Collection<?> c) {

       c.add(null); //编译通过

       c.add(“test”); //编译错误

}

       很好理解:c中要存放的对象的具体类型不确定,编译器无法验证待添加对象类型的正确性,因此不能加入对象实例;而null可以看作是任一个类的实例,因而允许加入。

       另外,尽管c中要存放的对象的类型不确定,但我们知道任何类都是Object子类,因此从c中取出的对象都统一作为Object实例。

       更进一步,如果BaseClass代表某个可被继承的类的类名,那么Collection<? extends BaseClass>代表类型参数值为BaseClass或BaseClass某个子类的任一参数化Collection。对于Collection<? extends BaseClass>的实例c,因为c中要存放的对象具体类型不确定,不能往其加入非null对象,但从c中取出的对象都统一作为BaseClass实例。事实上,你可以把Collection<?>看作Collection<? extends Object>的简洁形式。

       另一种情形:如果SubClass代表任一个类的类名,那么Collection<? super SubClass>代表类型参数值为SubClass或SubClass某个祖先类的任一参数化Collection。对于Collection<? super SubClass>的实例c,你可以将SubClass实例加入其中,但从中取出的对象都是Object实例。

7 Generic方法
我们可以定义Generic类,同样可以定义Generic方法,即将方法的一个或多个参数的类型参数化,如代码:


public static <T> void fromArrayToCollection(T[] a, Collection<T> c) {

       for (T o : a) {

           c.add(o); //合法。注意与Collection<?>的区别

    }

}


我们可以以如下方式调用fromArrayToCollection():

Object[] oa = new Object[100];

Collection<Object> co = new ArrayList<Object>();

fromArrayToCollection(oa, co); //此时,T即为Object


String[] sa = new String[100];

Collection<String> cs = new ArrayList<String>();

fromArrayToCollection(sa, cs); //此时,T即为String

fromArrayToCollection(sa, co); //此时,T即为Object

Integer[] ia = new Integer[100];

Float[] fa = new Float[100];

Number[] na = new Number[100];

Collection<Number> cn = new ArrayList<Number>();

fromArrayToCollection(ia, cn); //此时,T即为Number

fromArrayToCollection(fa, cn); //此时,T即为Number

fromArrayToCollection(na, cn); //此时,T即为Number

fromArrayToCollection(na, co); //此时,T即为Object

fromArrayToCollection(na, cs); //编译错误

       通过以上代码可以看出,我们在调用fromArrayToCollection()时,无需明确指定T为何种类型(与Generic类的使用方式不同),而是像调用一般method一样,直接提供参数值,编译器会根据提供的参数值自动为T赋类型值或提示编译错误(参数值不当)。
考虑如下函数sum()
public static long sum(Collection<? extends Number> numbers) {
    long sum = 0;
    for (Number n : numbers) {
       sum += n.longValue();
    }
    return sum;
}

我们也可以将其以Generic方法实现:

public static <T extends Number> long sum(Collection<T> numbers) {

    long sum = 0;

    for (Number n : numbers) {

       sum += n.longValue();

    }

    return sum;
}

       那么对于一个方法,当要求参数类型可变时,是采用Generic方法,还是采用类型参数通配符方式呢?一般而言,如果参数类型间或参数类型与返回值类型间存在某种依赖关系,则采取Generic方法,否则采取类型参数通配符方式。

       这一原则在Collection类库的源代码中得到了很好的体现,例如Collection接口的containsAll()、addAll()和toArray()方法:


interface Collection<E> {

       public boolean containsAll(Collecion<?> c); //参数间类型以及参数与返回
                                                                    //值间类型无依赖
       <T> T[] toArray(T[] a); //参数a与返回值都是相同类的数组,有依赖
}

当然,根据需要,二者也可以结合使用,例如Collections中的copy()方法:

class Collections {

       public static <T> void copy(List<T> dest, List<? extends T> src) {

           …….

       }

}

你可能感兴趣的:(jdk)