文档章节

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

熊大熊二
 熊大熊二
发布于 2015/10/21 14:51
字数 3159
阅读 157
收藏 10
点赞 0
评论 1

译注:但见新人笑,哪闻旧人哭。在大家都在兴致勃勃的讨论Java 8的时候,那个早被遗忘的Java 7,或许你从来都没有记得它的好。


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表达式结合起来后,写出来的代码肯定会更加简洁。


类型推导

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钻石操作符的信息。(译注:原文没提供链接啊)


在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相比 ,编译器可以生成更高效的代码。更详细的说明请点击这里。


自动资源管理(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了。


Fork Join框架

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


数值字面量中使用下划线

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

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


在一个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)。


了解更多请点击这里。


使用"ob"前缀的二进制字面量

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还能够使用通配符来进行文件的搜索。你还可以用它来监测某个目录 是否有变动。我推荐你看下它的官方文档来了解更多的一些有意思的特性。


G1垃圾回收器

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


重抛异常的改进

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块中重新抛出异常,实际真正抛出的异常类型会是:


你的try块抛出的异常

还没有被前面的catch块处理过,并且

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。



本文转载自:http://it.deepinmind.com/java/2014/04/21/10-jdk-7-features-to-revisit-before-you-welcome-java-8.html

共有 人打赏支持
熊大熊二
粉丝 15
博文 29
码字总数 22587
作品 0
东城
程序员
加载中

评论(1)

如梦技术
如梦技术
79大将,学习了。
深入理解JAVA虚拟机学习笔记13——Class类文件的结构(1常量池)

前一篇文章已经对Class类文件匆匆一瞥,上一篇没看的,建议先看一下上一篇,这一篇就看一下具体的细节。 我们先随便创建一个类,代码如下。 运行main方法,这个时候会生成一个class文件,我们...

徐可心
06/07
0
0
Oracle Java SE 8 发行版更新:限制商业或生产用途

Oracle Java SE 8 发行版更新 Oracle Java SE 8 的公开更新仍面向单独的个人使用提供,至少持续至 2020 年底。 2019 年 1 月以后发布的 Oracle Java SE 8 公开更新将不向没有商用许可证的业务...

抢小孩糖吃
04/18
0
61
Java 8时间和日期API 20例

伴随lambda表达式、streams以及一系列小优化,Java 8 推出了全新的日期时间API,在教程中我们将通过一些简单的实例来学习如何使用新API。Java处理日期、日历和时间的方式一直为社区所诟病,将...

黄梦巍
2015/06/19
0
0
Java 8新特性探究 前言

自2013年6月13日,oracle就已经发布的Java 8特性完备版本(M7),但最终GA版本将在2014年3月18日(已第二次跳票,原计划今年9月发布的,据官网宣称是为了解决安全问题......),相信大家多多...

OSC闲人
2013/11/05
0
17
Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!

前几天写了一篇 Java 8 即将在 2019 年停止免费向企业提供更新的文章,企图迫使用户向更新一代的 Java 版本升级,但让人遗憾的是,小编今天收到了 Oracle Java 版本的升级推送,装完居然是 ...

Java技术栈
04/27
0
5
《Java从小白到大牛精简版》之第1章 开篇综述

Java诞生到现在已经有20多年了,但是Java仍然是非常热门的编程语言之一,很多平台中使用Java开发。表1-1所示的是TIOBE社区发布的2016年5月和2017年5月的编程语言排行榜,可见Java语言的热度,...

tony关东升
06/26
0
0
重磅!Java 性能监控调试工具 JMC 宣布开源

JRockit JVM 创始人之一、Oracle Java 产品组成员 Marcus Hirt 昨日在其博客上宣布,Java Mission Control(JMC)的源代码已正式开源。 JMC 是源自 JRockit JVM 的一套监控和管理工具,Oracl...

王练
05/07
0
6
做几道基础的Java测试题,看看最近有进步吗?欢迎来学习

Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互...

启示录是真的
05/24
0
0
用 JNI 进行 Java 编程(5)

结束语和参考资料 结束语 Java 本机接口是 Java 平台中一种设计良好和良好集成的 API。它被设计成用来使您能将本机代码合并到 Java 程序中,也为您提供了一种在用其它编程语言编写的程序中使...

Jerikc
2012/10/08
0
0
天了噜,Java 8 要停止维护了!

前些天的中兴事件,已经让国人意识到自己核心技术的不足,这次的 JDK 8 对企业停止免费更新更是雪上加霜。。 以下是 Oracle 官网提示的 JDK8 终止更新公告。 原文内容:Oracle will not pos...

Java技术栈
04/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

pbgo: 基于Protobuf的迷你RPC/REST框架

https://www.oschina.net/p/pbgo

chai2010
15分钟前
0
0
rsync工具介绍、常用选项以及通过ssh同步

linux下的文件同步工具 rsync rsync是非常实用的一个同步工具,可以从a机器到b机器传输一个文件,也可以备份数据,系统默认没有这个工具,要使用命令 yum install -y rsync 安装。 rsync的命...

黄昏残影
31分钟前
0
0
OSChina 周四乱弹 —— 表妹要嫁人 舅妈叮嘱……

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @哈哈哈哈哈嗝:一定要听——The Pancakes的单曲《咁咁咁》 《咁咁咁》- The Pancakes 手机党少年们想听歌,请使劲儿戳(这里) @clouddyy :...

小小编辑
今天
66
4
流利阅读笔记30-20180719待学习

重磅:让人类得老年痴呆的竟是它? Lala 2018-07-19 1.今日导读 去年奥斯卡最佳动画长片《寻梦环游记》里有一句经典台词:“比死亡更可怕的,是遗忘”。在电影中,年迈的曾祖母会重复说一样的...

aibinxiao
今天
3
0
1.16 Linux机器相互登录

Linux机器之间以密码方式互相登录 运行命令#ssh [ip address],标准命令:#ssh [username]@ip, 如果没有写用户名,则默认为系统当前登录的用户 命令#w查看系统负载,可查看到连接到该主机的...

小丑鱼00
今天
0
0
about git flow

  昨天元芳做了git分支管理规范的分享,为了拓展大家关于git分支的认知,这里我特意再分享这两个关于git flow的链接,大家可以看一下。 Git 工作流程 Git分支管理策略   git flow本质上是...

qwfys
今天
2
0
Linux系统日志文件

/var/log/messages linux系统总日志 /etc/logrotate.conf 日志切割配置文件 参考https://my.oschina.net/u/2000675/blog/908189 dmesg命令 dmesg’命令显示linux内核的环形缓冲区信息,我们可...

chencheng-linux
今天
1
0
MacOS下给树莓派安装Raspbian系统

下载镜像 前往 树莓派官网 下载镜像。 点击 最新版Raspbian 下载最新版镜像。 下载后请,通过 访达 双击解压,或通过 unzip 命令解压。 检查下载的文件 ls -lh -rw-r--r-- 1 dingdayu s...

dingdayu
今天
1
0
spring boot使用通用mapper(tk.mapper) ,id自增和回显等问题

最近项目使用到tk.mapper设置id自增,数据库是mysql。在使用通用mapper主键生成过程中有一些问题,在总结一下。 1、UUID生成方式-字符串主键 在主键上增加注解 @Id @GeneratedValue...

北岩
今天
2
0
告警系统邮件引擎、运行告警系统

告警系统邮件引擎 cd mail vim mail.py #!/usr/bin/env python#-*- coding: UTF-8 -*-import os,sysreload(sys)sys.setdefaultencoding('utf8')import getoptimport smtplibfr......

Zhouliang6
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部