`

Java 8?还记得那年大明湖畔的Java 7吗?

    博客分类:
  • java
 
阅读更多
Java 8的发布也有一个月了,我相信现在大家都在探索JDK 8中的新特性。但是,在你彻底开始钻研Java 8之前,最好先来回顾下Java 7有哪些新特性。如果你还记得的话,Java 6是没有增加任何特性的,只是JVM的一些改动以及性能的提升,不过JDK 7倒是增加了不少有助于提升开发效率的很给力的特性。我现在写这篇文章的目的是什么呢?为什么别人都在讨论Java 8的时候,我却还在聊Java1.7的事?因为我认为并不是所有的Java开发人员都很清楚JDK 7中的改动,还有什么时候比新版本发布的时候更适合介绍上一版本的特性的呢?我还很少看见有开发人员在代码中使用自动资源管理(ARM),尽管IDE的辅助工具都已经支持这个特性了。不过确实看到有人在用string的switch功能以及<>在做类型推导,另外,也很少有人知道fork-join框架,或者在一个catch块里捕获多个异常,或者在数值型字面量中使用下划线。因此我借这个机会来写一篇简短的摘要,回顾一下这些能方便我们日常开发工作的改动。NIO以及新的文件接口,还有很多API层面的改动也同样值得关注。我相信和Java 8的lambda表达式结合起来后,写出来的代码肯定会更加简洁。

1.  类型推导

JDK 1.7引入一个新的操作符<>,也被称作钻石操作符,它使得构造方法也可以进行类型推导 。在Java 7之前,类型推导只对方法可用,正如Joshua Bloch在_Effiective Java_第二版中所预言 的那样,现在终于在构造方法中实现了。在这之前,你得在对象创建表达式的左右两边同时指定类型,现在你只需要在左边指定就可以了,就像下面这样。

JDK 7之前

Map<String, List<String>> employeeRecords =  new HashMap<String, List<String>>();  
List<Integer> primes = new ArrayList<Integer>(); 



JDK 7

Map<String, List<String>> employeeRecords =  new HashMap<>();  
List<Integer> primes = new ArrayList<>(); 



在Java 7中可以少敲些代码了,尤其是在使用集合的时候,因为那里大量用到了泛型。点击这里了解更多关于Java钻石操作符的信息。(译注:原文没提供链接啊)

2. 在switch中支持String

在JDK 7之前 ,只有整型才能用作switch-case语句的选择因子。在JDK7中,你可以将String用作选择因子了。比如:

String state = "NEW";  
   
switch (day) {  
   case "NEW": System.out.println("Order is in NEW state"); break;  
   case "CANCELED": System.out.println("Order is Cancelled"); break;  
   case "REPLACE": System.out.println("Order is replaced successfully"); break;  
   case "FILLED": System.out.println("Order is filled"); break;  
   default: System.out.println("Invalid");  
 }  



比较的时候会用到String的equals和hashCode()方法,因此这个比较是大小写敏感的。在switch中使用String的好处是,和直接用if-else相比 ,编译器可以生成更高效的代码。更详细的说明请点击这里。

3. 自动资源管理(Automatic Resource Management)

在JDK 7之前,我们需要使用一个finally块,来确保资源确实被释放掉,不管try块是完成了还是中断了。比如说读取文件或者输入流的时候,我们需要在finally块中关闭它们,这样会导致很多的样板代码,就像下面这样:

public static void main(String args[]) {  
        FileInputStream fin = null;  
        BufferedReader br = null;  
        try {  
            fin = new FileInputStream("info.xml");  
            br = new BufferedReader(new InputStreamReader(fin));  
            if (br.ready()) {  
                String line1 = br.readLine();  
09  
                System.out.println(line1);  
            }  
        } catch (FileNotFoundException ex) {  
            System.out.println("Info.xml is not found");  
        } catch (IOException ex) {  
            System.out.println("Can't read the file");  
        } finally {  
            try {  
                if (fin != null) fin.close();  
                if (br != null) br.close();  
            } catch (IOException ie) {  
                System.out.println("Failed to close files");  
            }  
        }  
    } 



看下这段代码 ,是不是很多样板代码?

而在Java 7里面,你可以使用try-with-resource的特性来自动关闭资源,只要是实现了AutoClosable和Cloaeable接口的都可以,Stream, File, Socket,数据库连接等都已经实现了。JDK 7引入了try-with-resource语句,来确保每个资源在语句结束后都会调用AutoCLosable接口的close()方法进行关闭。下面是Java 7中的一段示例代码,它看起来可是简洁多了:

public static void main(String args[]) {  
       try (FileInputStream fin = new FileInputStream("info.xml");  
  BufferedReader br = new BufferedReader(new InputStreamReader(fin));) {  
  if (br.ready()) {  
   String line1 = br.readLine();  
   System.out.println(line1);  
  }  
 } catch (FileNotFoundException ex) {  
  System.out.println("Info.xml is not found");  
 } catch (IOException ex) {  
  System.out.println("Can't read the file");  
 }  
} 



由于Java负责关闭那些打开的资源比如文件和流这种,因此文件描述符泄露的事情应该不会再发生了,应该也不会再看到文件描述符错误的提示了。甚至JDBC 4.1都已经开始支持了AutoClosable了。

4. Fork Join框架

Fork/join框架是ExecutorService接口的实现,它使得你可以充分利用现代服务器多处理器带来的好处。这个框架是为了那些能递归地拆分成更小任务的工作而设计的。它的目标是去压榨处理器的能力以提升程序的性能。就像别的ExecutorService的实现一样,fork/join框架也是把任务分发给线程池中的多个线程。它的不同之处在于它使用的是一种工作窃取算法(work-stealing algorithm),这和生产者消费者的算法有很大的不同。已经处理完任务的工作线程可以从别的繁忙的线程那里窃取一些任务来执行。fork/join框架的核心是ForkJoinPool类,它继承自AbstractExecutorService。ForkJoinPool类实现了核心的工作窃取算法,可以执行ForkJoinTask进程。你可以把代码封装在一个ForkJoinTask的子类里,比如RecursiveTask或者RecursiveAction。更多信息就参考这里。

5. 数值字面量中使用下划线

JDK 7中,你可以在数值字面量中使用'_'来提升可读性。这对在源代码中使用了大数字的人来说尤其有用,例如在金融或者计算领域中。比方说这么写,

int billion = 1_000_000_000;  // 10^9  
long creditCardNumber =  1234_4567_8901_2345L; //16 digit number  
long ssn = 777_99_8888L;  
double pi = 3.1415_9265;  
float  pif = 3.14_15_92_65f;
 


你可以在合适的位置插入下划线使得它可读性更强,比如说一个很大的数字可以每隔三位放一个下划线,对于信用卡卡号而言,通常是16位长度,你可以每隔4个数字就放一个下划线,就如它们在卡片上所显示的那样。顺便说一句,要记住,你不能在小数后面,或者数字的开始和结束的地方放下划线。比如说,下面的数值字面量就是不正确的,因为它们错误地使用了下划线:

double pi = 3._1415_9265; // underscore just after decimal point  
long creditcardNum = 1234_4567_8901_2345_L; //underscore at the end of number  
long ssn = _777_99_8888L; //undersocre at the beginning  



你可以读下我的这篇文章了解更多的一些关于下划线使用的例子。

6. 在一个catch块中捕获多个异常

JDK 7中,单个catch块可以处理多个异常类型。

比如说在JDK 7之前,如果你想捕获两种类型的异常你得需要两个catch块,尽管两个的处理逻辑都是一样的:

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


而在JDK 7中,你只须使用一个catch块就搞定了,异常类型用‘|’进行分隔:

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



顺便说一句,这种用法是不包括异常的子类型的。比如说,下面这个多个异常的捕获语句就会抛出编译错误:

try {   
   ......  
  
} catch (FileNotFoundException | IOException ex) {  
   ex.printStackTrace();  
}
 


这是因为FileNotFoundException是IOException 的子类,在编译的时候会抛出下面的错误:
java.io.FileNotFoundException is a subclass of alternative java.io.IOException
        at Test.main(Test.java:18)。

了解更多请点击这里。

7. 使用"0b"前缀的二进制字面量

JDK7中,对于整型类型(byte, short, int 和long)来说,你可以用'0b'前缀来表明这是一个二进制的字面量,就像C/C++中那样。在这之前,你只能使用8进制(前缀'0')或者16进制(前缀是'0x'或者‘0X')的字面量。

int mask = 0b01010000101; 



这样写好处更明显:

int binary = 0B0101_0000_1010_0010_1101_0000_1010_0010;
 


8.Java NIO 2

Java SE 7中引入了java.nio.file包,以及相关的java.nio.file.attibute包,全面支持了文件IO以及对默认文件系统的访问。它同时还引入了Path 类,你可以用它来代表操作系统中的任意一个路径。新的文件系统API兼容老的版本,并且提供了几个 非常实用的方法,可以用来检查,删除,拷贝和移动文件。比如,你可以在Java中判断一个文件是否是隐藏文件。你还可以在Java中创建软链接和硬链接。JDK 7的新的文件API还能够使用通配符来进行文件的搜索。你还可以用它来监测某个目录 是否有变动。我推荐你看下它的官方文档来了解更多的一些有意思的特性。

9. G1垃圾回收器

JDK7中引入了一个新的垃圾回收器,G1,它是Garbage First的缩写。G1回收器优先回收垃圾最多的区域。为了实现这个策略它把堆分成了多个区域,就好比Java 7之前分成三个区域那样(新生代,老生代和持久代)。G1回收器是一个可预测的回收器,同时对那些内存密集型的程序它还能保证较高的吞吐量。

10. 重抛异常的改进

Java SE 7的编译器和之前的版本相比,在重新抛出异常这块进行了更精确的分析。这使得你在方法声明的throws子句中可以指定更精确的异常类型。在JDK 7之前,重抛的异常的类型被认为是catch参数中的指定的异常类型。比如说,如果你的try块中抛出了一个ParseException以及一个IOException,为了捕获所有的异常,然后重新抛出来,你会去捕获Exception类型的异常,并且声明你的方法抛出的异常类型是Exception。这种方式有点不太精确,因为你实际抛出的是一个通用的Exception类型,而调用你的方法的语句需要去捕获这个通用的异常。看一下Java 1.7前的这段异常处理的代码可能你会更明白些:

public void obscure() throws Exception{  
    try {  
        new FileInputStream("abc.txt").read();  
        new SimpleDateFormat("ddMMyyyy").parse("12-03-2014");         
    } catch (Exception ex) {  
        System.out.println("Caught exception: " + ex.getMessage());  
        throw ex;  
    }  
} 



JDK 7以后你就可以在方法的throws子句中明确的指定异常类型了。精确的异常重抛指的是,如果你在catch块中重新抛出异常,实际真正抛出的异常类型会是:

1. 你的try块抛出的异常
2. 还没有被前面的catch块处理过,并且
3. catch的参数类型是Exception的某个子类。

这使得异常重抛变得更精确。你可以更准确的知道方法抛出的是何种异常,因此你可以更好的处理它们,就像下面这段代码这样:

public void precise() throws ParseException, IOException {  
    try {  
        new FileInputStream("abc.txt").read();  
        new SimpleDateFormat("ddMMyyyy").parse("12-03-2014");         
    } catch (Exception ex) {  
        System.out.println("Caught exception: " + ex.getMessage());  
        throw ex;  
    }  
}  



Java SE 7的编译器允许你在preciese() 方法声明的throws子句中指定ParseException和IOException类型,这是因为你抛出的异常是声明的这些异常类型的父类,比如这里我们抛出的是java.lang.Exception,它是所有受检查异常的父类。有的地方你会看到catch参数中带final关键字,不过这个不再是强制的了。

这些就是JDK 7中所有你应该回顾的内容了。这些新特性对写出整洁的代码以及提升开发效率非常有用。有了Java 8中的lambda表达式,Java中的代码整洁之道则又上了一个新的里程碑。如果你认为我这篇文章中漏掉了Java 1.7任何有用的特性,请记得提醒我。


P.S. 如果你喜欢读书的话,那你也一定会喜欢Packet Publication的这本_Java 7 New features Cookbook_。
分享到:
评论

相关推荐

    大明湖畔早就没了夏雨荷.docx

    1. 《大明湖畔早就没了夏雨荷》引用的台词:这句话源自经典电视剧中的台词,反映了对过去的回忆和对某个人深深的情感纠葛,也成为了描述大明湖的一个文化符号。 2. 大明湖:位于中国山东省济南市,是一个著名的历史...

    大明湖畔 行业齐聚山东国际电动车新能源汽车展.pdf

    大明湖畔 行业齐聚山东国际电动车新能源汽车展.pdf

    大明王朝历代皇帝列表 在位多少年.docx

    大明王朝历代皇帝列表 在位多少年 大明王朝是中国历史上最后一个由汉人统治的封建王朝。该朝代的开创者朱元璋,也是历史上为数不多的白手起家的布衣皇帝之一。下面是大明王朝历代皇帝列表: 1. 朱元璋(1368年-...

    腾讯代理《大明龙权》全套策划案

    《大明龙权》是一款由腾讯代理的网络游戏,其全套策划案揭示了游戏从概念到实施的全过程,是深入了解游戏开发与运营的重要资料。在这个策划案中,我们可以探索到以下几个核心知识点: 1. **市场调研**:在策划初期...

    自动控制原理答案 蒋大明

    《自动控制原理答案》蒋大明一书,作为自动控制领域的精辟材料,不仅提供了深入浅出的理论解析,还附带了丰富的实践案例与习题解答,是学习和研究自动控制原理不可或缺的重要资源。自动控制原理是现代工程学中的核心...

    20210506-安信国际-大明国际-1090.HK-金属加工龙头大明国际:厚积薄发.pdf

    大明国际在2021年5月6日的PE-TTM估值为8.8倍,与港股和美股的相关对标公司相比,估值较低,存在上升空间。风险因素的出现可能会对公司的股价和市值产生影响。 总结来说,大明国际作为一家在金属加工行业有深厚积累...

    大明龙权验证码识别

    【大明龙权验证码识别】是一项技术挑战,主要涉及到计算机视觉和自动化处理领域的知识。在游戏《大明龙权》中,为了防止机器人或者非法脚本的滥用,开发者引入了验证码系统,这是一种安全机制,用来确保操作是由真实...

    之外创意郑大明作品集(部分)(43P)0722.pdf

    该作品集不仅记录了郑大明从2014年起的个人成长与专业积累,也映射了中国创意设计在不同领域中的创新与突破。作为之外创意的重要成员,郑大明的作品集在展现其个人风格的同时,也传递了团队共同的创意哲学和精神追求...

    安卓版大明商城客户端源代码

    【安卓版大明商城客户端源代码】是一款专为Android平台设计的电商应用源码,它类似于知名的淘宝客户端,集成了丰富的购物功能,旨在提供便捷、安全的在线购物体验。这款源代码具有高度可定制性,适合开发者进行二次...

    大明企业网络办公室软件

    【大明企业网络办公室软件】是一款专为企事业单位设计的高效办公解决方案,旨在提升团队协作效率,优化企业管理流程。这款软件集成了多种功能模块,包括但不限于客户关系管理、项目管理、文档共享、任务分配等,为...

    在家代理网吧ip的大明龙权道具领取器

    在家代理网吧ip的大明龙权道具领取器在家代理网吧ip的大明龙权道具领取器在家代理网吧ip的大明龙权道具领取器

    大明煤矿选煤厂煤尘治理实践

    在煤炭行业中,煤尘污染是一个长期且普遍存在的问题,其不仅影响工人的健康安全,还可能对周围环境造成严重的负面影响。针对大明煤矿选煤厂的煤尘污染问题,该文献提出并实践了一系列有效的防治措施,并取得了显著的...

    苏大明世:2021年半年度报告.rar

    《苏大明世2021年半年度报告》详细解析 报告概述: 这份报告是苏大明世公司在2021年上半年业务运营情况的全面总结。作为一家在信息技术行业中具有影响力的公司,苏大明世的半年度报告对于我们了解其业务发展、市场...

    Java运行程序代码段

    我记得那时候刚毕业。学习JAVA恐惧是这里,它是关于JAVA称号。我总是不正确。如今,这后审查。看了好半天。得赶紧把刚才学习到的那点东西记下来。  一、关于static的代码段运行顺序 package com.test; /** * ...

    java发送邮件

    Java发送邮件是一个常见的任务,通常用于自动化通知、报表发送或者用户验证等场景。要实现这个功能,你需要了解JavaMail API,这是一个广泛使用的Java库,它允许开发者通过SMTP(简单邮件传输协议)或者其他邮件协议...

    大明寺导游词.docx

    大明寺导游词.docx

    苏大明世:2021年半年度报告.PDF

    【苏州苏大明世光学股份有限公司2021年半年度报告】反映了公司在该时期的经营状况和重要事件。报告中提到的关键知识点主要包括: 1. **股东及控股股东变更**:2021年4月26日,北京超视信息技术有限公司通过大宗交易...

    大明猩电影中小学观后感2021年5篇.docx

    在2021年,一部名为《大明猩》的3D电影以其独特的魅力和深刻的情感,给众多中小学师生留下了深刻的印象。这部影片是由中韩两国携手打造的科幻动作电影,它不仅在电影技术上做出了创新,更是巧妙地融合了教育元素,为...

    虞大明母鸡教学实录.docx

    在探索小学语文教学的道路上,虞大明老师以其独特的教学策略和方法,给我们带来了一份生动的教学实录——《虞大明母鸡教学实录》。这篇文章不仅仅记录了一堂课的进行过程,更是展现了虞大明老师在教授人教版四年级...

    开发工程师-褚大明.xlsm

    开发工程师-褚大明.xlsm

Global site tag (gtag.js) - Google Analytics