Java JDK1.5、1.6、1.7新特性整理
一、JavaJDK1.5的新特性
1.泛型:
List<String>strs=newArrayList<String>();//给集合指定存入类型,上面这个集合在存入数据的时候必须存入String类型的数据,否则编译器会报错
2.for-each
例如上面这个集合我们可以通过for-each遍历,这样更加简单清晰
for(Strings:strs){ System.out.println(s); }
注意:使用for-each遍历集合时,要遍历的集合必须实现了Iterator接口
3.自动拆箱和装箱功能
什么意思呢? JDK1.5为每一个基本数据类型定义了一个封装类。使java中的基本数据类型也有自己的对象 例如:int-->Integer, double-->Double, long-->Long, char-->Character, float-->Float, boolean-->Boolean, short-->Short, byte-->Byte 自动装包:将基本类型转换成为对象,例如:int-->Integer 自动拆包:将对象转换成为基本数据类型,例如:Integer-->int 对于JDK1.5之前集合总不能存放基本数据类型的问题,现在也能够解决。
4.枚举:
枚举是JDK1.5推出的一个比较中要的特性。其关键字为enum
例如:定义代表交通灯的枚举
publicenumMyEnum{ RED,GREEN,YELLOW }
5.可变参数
什么意思呢?先举个例子:在JDK1.5以前,当我们要为一个方法传递多个类型相同的参数时,我们有两种方法解决,1.直接传递一个数组过去,2.有多少个参数就传递多少个参数。
例如:
publicvoidprintColor(Stringred,Stringgreen,Stringyellow){ }
或者
publicvoidprintColor(String[]colors){ }
这样编写方法参数虽然能够实现我们想要的效果,但是,这样是不是有点麻烦呢?再者,如果参数个数不确定,我们怎么办呢?JavaJDK1.5为我们提供的可变参数就能够完美的解决这个问题
例如:
publicvoidprintColor(String...colors){ }
可以这样定义,什么意思呢?如果参数的类型相同,那么可以使用“类型+三个点,后面跟一个参数名称”的形式。这样的好处就是,只要参数类型相同,无论传递几个参数都没有限制
注意:可变参数必须是参数列表的最后一项(该特性对对象和基本数据类型都适用)
6.静态导入
优点:使用静态导入可以使被导入类的所有静态变量和静态方法在当前类直接可见,使用这些静态成员无需再给出他们的类名。
缺点:过度使用会降低代码的可读性
7.线程并发库
线程并发库是Java1.5提出的关于多线程处理的高级功能,所在包:java.util.concurrent
包括
1.线程互斥
工具类描述:Lock,RedWriteLock
2.线程通信
描述:Condition
3.线程池
ExecutorService
3.同步队列
ArrayBlockingQueue
4.同步集合
ConcurrentHashMap,CopyOnWriteArrayList
5.线程同步工具
Semaphore
关于线程并发库的内容还有很多(很重要),这里就不一一列举了,感兴趣的朋友可以查看一下帮助文档。
二、JDK1.6新特性
1.Desktop类和SystemTray类
前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档;后者可以用来在系统托盘区创建一个托盘程序。
2.使用JAXB2来实现对象与XML之间的映射
JAXB是JavaArchitectureforXMLBinding的缩写,可以将一个Java对象转变成为XML格式,反之亦然。
我们把对象与关系数据库之间的映射称为ORM,其实也可以把对象与XML之间的映射称为OXM(ObjectXMLMapping)。原来JAXB是JavaEE的一部分,在JDK1.6中,SUN将其放到了JavaSE中,这也是SUN的一贯做法。JDK1.6中自带的这个JAXB版本是2.0,比起1.0(JSR31)来,JAXB2(JSR222)用JDK5的新特性Annotation来标识要作绑定的类和属性等,这就极大简化了开发的工作量。实际上,在JavaEE5.0中,EJB和WebServices也通过Annotation来简化开发工作。另外,JAXB2在底层是用StAX(JSR173)来处理XML文档。
除了JAXB之外,我们还可以通过XMLBeans和Castor等来实现同样的功能。
3.理解StAX
StAX(JSR173)是JDK1.6.0中除了DOM和SAX之外的又一种处理XML文档的API。
StAX的来历:在JAXP1.3(JSR206)有两种处理XML文档的方法:DOM(DocumentObjectModel)和SAX(SimpleAPIforXML)。
由于JDK1.6.0中的JAXB2(JSR222)和JAX-WS2.0(JSR224)都会用到StAX所以Sun决定把StAX加入到JAXP家族当中来,并将JAXP的版本升级到1.4(JAXP1.4是JAXP1.3的维护版本)。JDK1.6里面JAXP的版本就是1.4。StAX是TheStreamingAPIforXML的缩写,一种利用拉模式解析(pull-parsing)XML文档的API.StAX通过提供一种基于事件迭代器(Iterator)的API让程序员去控制xml文档解析过程,程序遍历这个事件迭代器去处理每一个解析事件,解析事件可以看做是程序拉出来的,也就是程序促使解析器产生一个解析事件然后处理该事件,之后又促使解析器产生下一个解析事件,如此循环直到碰到文档结束符;SAX也是基于事件处理xml文档,但却是用推模式解析,解析器解析完整个xml文档后,才产生解析事件,然后推给程序去处理这些事件;DOM采用的方式是将整个xml文档映射到一颗内存树,这样就可以很容易地得到父节点和子结点以及兄弟节点的数据,但如果文档很大,将会严重影响性能。
4.使用CompilerAPI
现在我们可以用JDK1.6的CompilerAPI(JSR199)去动态编译Java源文件,CompilerAPI结合反射功能就可以实现动态的产生Java代码并编译执行这些代码,有点动态语言的特征。
这个特性对于某些需要用到动态编译的应用程序相当有用,比如JSPWebServer,当我们手动修改JSP后,是不希望需要重启WebServer才可以看到效果的,这时候我们就可以用Compiler API来实现动态编译JSP文件,当然,现在的JSPWebServer也是支持JSP热部署的,现在的JSPWebServer通过在运行期间通过Runtime.exec或ProcessBuilder来调用javac来编译代码,这 种方式需要我们产生另一个进程去做编译工作,不够优雅而且容易使代码依赖与特定的操作系统;CompilerAPI通过一套易用的标准的API提供了更加丰富的方式去做动态编译,而且是跨平 台的。
5.轻量级HttpServerAPI
JDK1.6提供了一个简单的HttpServerAPI,据此我们可以构建自己的嵌入式HttpServer,它支持Http和Https协议,提供了HTTP1.1的部分实现,没有被实现的那部分可以通过扩展已有的HttpServerAPI来实现,程序员必须自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,在这里,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给HttpHandler实现类的回调方法。
6.插入式注解处理API(PluggableAnnotationProcessingAPI)
插入式注解处理API(JSR269)提供一套标准API来处理Annotations(JSR175)
实际上JSR269不仅仅用来处理Annotation,我觉得更强大的功能是它建立了Java语言本身的一个模型,它把method,package,constructor,type,variable,enum,annotation等Java语言元素映射为Types和Elements(两者有什么区别?),从而将Java语言的语义映射成为对象,我们可以在javax.lang.model包下面可以看到这些类。所以我们可以利用JSR269提供的API来构建一个功能丰富的元编程(metaprogramming)环境。JSR269用AnnotationProcessor在编译期间而不是运行期间处理Annotation,AnnotationProcessor相当于编译器的一个插件,所以称为插入式注解处理.如果AnnotationProcessor处理Annotation时(执行process方法)产生了新的Java代码,编译器会再调用一次AnnotationProcessor,如果第二次处理还有新代码产生,就会接着调用AnnotationProcessor,直到没有新代码产生为止.每执行一次process()方法被称为一个"round",这样整个Annotationprocessing过程可以看作是一个round的序列。
JSR269主要被设计成为针对Tools或者容器的API.举个例子,我们想建立一套基于Annotation的单元测试框架(如TestNG),在测试类里面用Annotation来标识测试期间需要执行的测试方法
7.用Console开发控制台程序
JDK1.6中提供了java.io.Console类专用来访问基于字符的控制台设备。你的程序如果要与Windows下的cmd或者Linux下的Terminal交互,就可以用Console类代劳。但我们不总是能得到可用的Console,一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用。如果JVM是在交互式命令行(比如Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实例。
8.对脚本语言的支持
如:ruby,groovy,javascript。
9.CommonAnnotations
Commonannotations原本是JavaEE5.0(JSR244)规范的一部分,现在SUN把它的一部分放到了JavaSE6.0中。
随着Annotation元数据功能(JSR175)加入到JavaSE5.0里面,很多Java技术(比如EJB,WebServices)都会用Annotation部分代替XML文件来配置运行参数(或者说是支持声明式编程,如EJB的声明式事务),如果这些技术为通用目的都单独定义了自己的otations,显然有点重复建设,所以,为其他相关的Java技术定义一套公共的Annotation是有价值的,可以避免重复建设的同时,也保证JavaSE和JavaEE各种技术的一致性。
下面列举出CommonAnnotations1.0里面的10个AnnotationsCommonAnnotationsAnnotationRetentionTargetDescriptionGeneratedSourceANNOTATION_TYPE,CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE用于标注生成的源代码ResourceRuntimeTYPE,METHOD,FIELD用于标注所依赖的资源,容器据此注入外部资源依赖,有基于字段的注入和基于setter方法的注入两种方式ResourcesRuntimeTYPE同时标注多个外部依赖,容器会把所有这些外部依赖注入PostConstructRuntimeMETHOD标注当容器注入所有依赖之后运行的方法,用来进行依赖注入后的初始化工作,只有一个方法可以标注为PostConstructPreDestroyRuntimeMETHOD当对象实例将要被从容器当中删掉之前,要执行的回调方法要标注为PreDestroyRunAsRuntimeTYPE用于标注用什么安全角色来执行被标注类的方法,这个安全角色必须和Container的Security角色一致的。RolesAllowedRuntimeTYPE,METHOD用于标注允许执行被标注类或方法的安全角色,这个安全角色必须和Container的Security角色一致的PermitAllRuntimeTYPE,METHOD允许所有角色执行被标注的类或方法DenyAllRuntimeTYPE,METHOD不允许任何角色执行被标注的类或方法,表明该类或方法不能在JavaEE容器里面运行DeclareRolesRuntimeTYPE用来定义可以被应用程序检验的安全角色,通常用isUserInRole来检验安全角色。
注意:
1.RolesAllowed,PermitAll,DenyAll不能同时应用到一个类或方法上标注在方法上的RolesAllowed,PermitAll,DenyAll会覆盖标注在类上的 RolesAllowed,PermitAll,DenyAllRunAs,RolesAllowed,PermitAll,DenyAll和DeclareRoles还没有加到JavaSE6.0上来处理以上Annotations的工作是由JavaEE容器来做,JavaSE6.0只是包含了上面表格的前五种Annotations的定义类,并没有包含处理这些Annotations的引擎,这个工作可以由PluggableAnnotationProcessingAPI(JSR269)来做。
相对于1.6的新特性,1.7的新特性更加令我们心动,因为它是我们期待已久的而且看得见摸得着的。
三、JDK1.7的新特性
1.二进制面值
在java7里,整形(byte,short,int,long)类型的值可以用二进制类型来表示了,在使用二进制的值时,需要在前面加上ob或oB,例如:
inta=0b01111_00000_11111_00000_10101_01010_10; shortb=(short)0b01100_00000_11111_0; bytec=(byte)0B0000_0001;
2.数字变量对下滑线的支持
JDK1.7可以在数值类型的变量里添加下滑线。
但是有几个地方是不能添加的
1.数字的开头和结尾
2.小数点前后
3.F或者L前
例如:
intnum=1234_5678_9;
floatnum2=222_33F;
longnum3=123_000_111L;
3.switch对String的支持
之前就一直有一个打问号?为什么C#可以Java却不行呢?哈,不过还有JDK1.7以后Java也可以了
例如:
Stringstatus="orderState"; switch(status){ case"ordercancel": System.out.println("订单取消"); break; case"orderSuccess": System.out.println("预订成功"); break; default: System.out.println("状态未知"); }
4.try-with-resource
try-with-resources是一个定义了一个或多个资源的try声明,这个资源是指程序处理完它之后需要关闭它的对象。try-with-resources确保每一个资源在处理完成后都会被关闭。
可以使用try-with-resources的资源有:
任何实现了java.lang.AutoCloseable接口java.io.Closeable接口的对象。
例如:
publicstaticStringreadFirstLineFromFile(Stringpath)throwsIOException{ try(BufferedReaderbr=newBufferedReader(newFileReader(path))){ returnbr.readLine(); } }
在java7以及以后的版本里,BufferedReader实现了java.lang.AutoCloseable接口。
由于BufferedReader定义在try-with-resources声明里,无论try语句正常还是异常的结束,它都会自动的关掉。而在java7以前,你需要使用finally块来关掉这个对象。
5.捕获多种异常并用改进后的类型检查来重新抛出异常
例如:
publicstaticvoidfirst(){ try{ BufferedReaderreader=newBufferedReader(newFileReader("")); Connectioncon=null; Statementstmt=con.createStatement(); }catch(IOException|SQLExceptione){ //捕获多个异常,e就是final类型的 e.printStackTrace(); } }
优点:用一个catch处理多个异常,比用多个catch每个处理一个异常生成的字节码要更小更高效。
6.创建泛型时类型推断
只要编译器可以从上下文中推断出类型参数,你就可以用一对空着的尖括号<>来代替泛型参数。这对括号私下被称为菱形(diamond)。在JavaSE7之前,你声明泛型对象时要这样
List<String>list=newArrayList<String>();
而在JavaSE7以后,你可以这样
List<String>list=newArrayList<>();
因为编译器可以从前面(List)推断出推断出类型参数,所以后面的ArrayList之后可以不用写泛型参数了,只用一对空着的尖括号就行。当然,你必须带着”菱形”<>,否则会有警告的。
JavaSE7只支持有限的类型推断:只有构造器的参数化类型在上下文中被显著的声明了,你才可以使用类型推断,否则不行。
List<String>list=newArrayList<>(); list.add("A"); //这个不行 list.addAll(newArrayList<>()); //这个可以 List<?extendsString>list2=newArrayList<>(); list.addAll(list2);
7.(无)
8.新增一些取环境信息的工具方法
例如:
FileSystem.getUserHomeDir()//当前用户目录 FileSystem.getUserDir()//启动java进程时所在的目录5 FileSystem.getJavaIoTempDir()//IO临时文件夹 FileSystem.getJavaHomeDir()//JRE的安装目录
9.安全的加减乘除
例如:
intMath.safeToInt(longvalue) intMath.safeNegate(intvalue) longMath.safeSubtract(longvalue1,intvalue2) longMath.safeSubtract(longvalue1,longvalue2) intMath.safeMultiply(intvalue1,intvalue2) longMath.safeMultiply(longvalue1,intvalue2) longMath.safeMultiply(longvalue1,longvalue2) longMath.safeNegate(longvalue) intMath.safeAdd(intvalue1,intvalue2) longMath.safeAdd(longvalue1,intvalue2) longMath.safeAdd(longvalue1,longvalue2) intMath.safeSubtract(intvalue1,intvalue2)
好吧,到目前为止就整理这么多。以后看到了,我会再添加上去的。
要注意的是:在不确定你之前的jdk版本时新的特性不要使用,不然的话就有可能出现这样或者那样的问题。