Java 7 新特性

题:Java 7 新特性 -- 实战篇


发表时间:2011-08-09 最后修改:2011-08-09

引用收藏


<>猎头职位: 北京: ITeye网站诚聘Ruby工程师

相关文章: 关于String字面常量的问题
JAVA6可以使用字符串累加
从其他地方移来的Java面题,欢迎讨论……

推荐群组: 高级语言虚拟机
更多相关推荐 “举世瞩目”的java 7近日发布,oracle网站上列出了java 语言的新特性 https://www.360docs.net/doc/cd10465888.html,/technetwork/java/javase/jdk7-relnotes-418459.html,最近出差,晚上闲来无事,将这些java语言的新特性试了下,very cool。
下面介绍了java 7的一些新特性,翻译自oracle网站,结合自己的实战。对Java 7研究不深,以下内容有对有错,欢迎大家批评指正,共同学习!

环境: ubuntu 11.04+eclipse 3.8
本来是用netbeans7.0.1,可是非常难用(不习惯 netBeans),加之用了几天之后,eclipse3.8推出,也支持java7,就切换到了更熟悉的eclipse下。顺便说一句,ubuntu11.04界面做的挺不错的,非常喜欢(附图是win 7下的无缝模式)。

java 7下载: https://www.360docs.net/doc/cd10465888.html,/technetwork/java/javase/downloads/index.html
eclipse 3.8下载: https://www.360docs.net/doc/cd10465888.html,/eclipse/downloads/drops/S-3.8M1-201108031800/
Netbeans 7.0.1 下载:https://www.360docs.net/doc/cd10465888.html,/downloads/start.html?platform=linux&lang=zh_CN&option=javaee


特性1:二进制字面值(Binary Literals)

在java7里,整形(byte,short,int,long)类型的值可以用二进制类型来表示了,在使用二进制的值时,需要在前面加上ob或oB,看代码



Java代码
//b 大小写都可以
int a = 0b01111_00000_11111_00000_10101_01010_10;
short b = (short)0b01100_00000_11111_0;
byte c = (byte)0B0000_0001;



其次,二进制同十进制和十六进制相比,可以一目了然的看出数据间的关系。例如下面这个数组中展示了每次移动一位后数字的变化。




Java代码
public static final int[] phases = {
0b00110001,
0b01100010,
0b11000100,
0b10001001,
0b00010011,
0b00100110,
0b01001100,
0b10011000
}

如果用十六进制来表示的,它们之间的关系就无法一眼看出来了。



Java代码
public static final int[] phases = {
0x31, 0x62, 0xC4, 0x89, 0x13, 0x26, 0x4C, 0x98
}


特性2:数字变量对下划线_的支持

你可以在数值类型的变量里添加下滑线,除了以下的几个地方不能添加:
数字的开头和结尾
小数点前后
F或者L前
需要出现string类型值的地方(针对用0x或0b表示十六进制和二进制,参考第一点),比如0x101,不能用0_x101



Java代码
int num = 1234_5678_9;
float num2 = 222_33F;
long num3 = 123_000_111L;

//下面的不


//数字开头和结尾
int nu = _123;
int nu = 123_;
//小数点前后
float f = 123_.12;
float f = 123._12;
//F或者L前
long l = 123_L;
float f = 123_F;
//需要出现String的地方
int num = 0_b123;
float f = 0_x123F;


这个,我个人觉得没什么实际作用,只是可以提升代码的可读性。

特性3:switch 对String的支持

这个大家期待很久了,switch终于支持String了




Java代码
public static void first() {
//项目状态
String status = "approval";
//我们之前经常根据项目状态不同来进行不同的操作
//目前已经换成enum类型

switch (status) {
case "shouli":
System.out.println("状态是受理");
break;
case "approval":
System.out.println("状态是审批");
break;
case "finish":
System.out.println("状态是结束");
break;
default:
System.out.println("状态未知");
}
}


每个case是使用String的equals方法来进行比较的,对大小写敏感。

和一连串的if-else-then想比,使用switch来计较String,Java编译器会生成更加有效的字节码,写一个例子测试一下。




Java代码
public static void second() {
String status = "approval";
if ("shouli".equals(status)) {
System.out.println("状态是受理");
} else if ("approval".equals(status)) {
System.out.println("状态是审批");
} else if ("finish".equals(status)) {
System.out.println("状态是结束");
} else {
System.out.println("状态未知");
}
}

使用javap之后,生成字节码如下:
switch



Java代码
public static void first();
Code:
0: ldc #2 // String approval
2: astore_0
3: aload_0
4: astore_1
5: iconst_m1
6: istore_2
7: aload_1
8: invokevirtual #3 // Method java/lang/String.hashCode:()I
11: lookupswitch { // 3
-1274442605: 72
-903146056: 44
1185244739: 58
default: 83
}
44: aload_1
45: ldc #4 // String shouli
47: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
50: ifeq 83
53: iconst_0
54: istore_2
55: goto 83
58: aload_1
59: ldc #2 // String approval
61: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
64: ifeq 83

67: iconst_1
68: istore_2
69: goto 83
72: aload_1
73: ldc #6 // String finish
75: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
78: ifeq 83
81: iconst_2
82: istore_2
83: iload_2
84: tableswitch { // 0 to 2
0: 112
1: 123
2: 134
default: 145
}
112: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
115: ldc #8
117: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
120: goto 153
123: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
126: ldc #10
128: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
131: goto 153
134: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
137: ldc #11
139: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
142: goto 153
145: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
148: ldc #12
150: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
153: return


用if-else串生成的字节码



Java代码
public static void second();
de:
0: ldc #2 // String approval
2: astore_0
3: ldc #4 // String shouli
5: aload_0
6: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
9: ifeq 23
12: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #8
17: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: goto 71
23: ldc #2 // String approval
25: aload_0
26: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
29: ifeq 43
32: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
35: ldc #10
37: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: goto 71
43: ldc #6 // String finish
45: aload_0
46: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
49: ifeq

63
52: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
55: ldc
57: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
60: goto 71
63: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
66: ldc #12
68: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
71: return

网上说,用switch之后比用if-else生成的字节码更有效一些,不过目前至少从长度上来说,switch还是长一些


特性4:try-with-resources 声明

try-with-resources 是一个定义了一个或多个资源的try 声明,这个资源是指程序处理完它之后需要关闭它的对象。try-with-resources 确保每一个资源在处理完成后都会被关闭。
可以使用try-with-resources的资源有:
任何实现了https://www.360docs.net/doc/cd10465888.html,ng.AutoCloseable 接口和java.io.Closeable 接口的对象。

来看例子:



Java代码
public static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}

在java 7 以及以后的版本里,BufferedReader实现了https://www.360docs.net/doc/cd10465888.html,ng.AutoCloseable接口。



Java代码
try (Closeable obj = new Closeable() {
@Override
public void close() throws IOException {
// do something
}
}) {
// do something
}

try (AutoCloseable obj = new AutoCloseable() {
@Override
public void close() throws IOException {
// do something
}
}) {
// do something
}



由于BufferedReader定义在try-with-resources 声明里,无论try语句正常还是异常的结束,它都会自动的关掉。而在java7以前,你需要使用finally块来关掉这个对象。




Java代码
public static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}


然而,如果 readLine() 和 close() 这两个方法都抛出异常,那么readFirstLineFromFileWithFinallyBlock 方法只会抛出后面部分也就是finally块中的内容,try块中的异常就被抑制了,对于我们的程序来说,这显然不是一种好的方式。
而在java 7中,无论是try块还是try-with-resource中抛出异常,readFirstLineFromFile会捕捉到try块的异常,try-with-resources中中异常被禁止了。在java 7 中,你能捕捉到被禁止的异常。后面会介绍。

另外,一个try-with-resourcse声明了可以包含多个对象的声明,用分号隔开,和声明一个对象相同,

会在结束后自动调用close方法,调用顺序和生命顺序相反。



Java代码
try (
java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
) {
// do something
}


此外,try-with-resources 可以跟catch和finally,catch和finally的是在try-with-resources里声明的对象关闭之后才执行的。


特性5:捕获多种异常并用改进后的类型检查来重新抛出异常

1、捕获多种异常

在Java SE7里,一个catch可以捕获多个异常,这样可以减少重复代码。每个异常之间用 | 隔开。



Java代码
public static void first(){
try {
BufferedReader reader = new BufferedReader(new FileReader(""));
Connection con = null;
Statement stmt = con.createStatement();
} catch (IOException | SQLException e) {
//捕获多个异常,e就是final类型的
e.printStackTrace();
}
}

而在Java SE6以前,需要这样写



Java代码
public static void second() {
try {
BufferedReader reader = new BufferedReader(new FileReader(""));
Connection con = null;
Statement stmt = con.createStatement();
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}


注意,如果一个catch处理了多个异常,那么这个catch的参数默认就是final的,你不能在catch块里修改它的值。
另外,用一个catch处理多个异常,比用多个catch每个处理一个异常生成的字节码要更小更高效。

使用一个catch生成的字节码



Java代码
public static void first();
Code:
0: new #2 // class java/io/BufferedReader
3: dup
4: new #3 // class java/io/FileReader
7: dup
8: ldc #4 // String
10: invokespecial #5 // Method java/io/FileReader."":(Ljava/lang/String;)V
13: invokespecial #6 // Method java/io/BufferedReader."":(Ljava/io/Reader;)V
16: astore_0
17: aconst_null
18: astore_1
19: aload_1
20: invokeinterface #7, 1 // InterfaceMethod java/sql/Connection.createStatement:()Ljava/sql/Statement;
25: astore_2
26: goto 34
29: astore_0
30: aload_0
31: invokevirtual #10 // Method java/lang/Exception.printStackTrace:()V
34: return
Exception table:
from to target type
0 26 29 Class java/io/IOException
0 26 29 Class java/sql/SQLException


使用两个catch生成的字节码



Java代码
public s

tatic void second();
Code:
0: new #2 // class java/io/BufferedReader
3: dup
4: new #3 // class java/io/FileReader
7: dup
8: ldc #4 // String
10: invokespecial #5 // Method java/io/FileReader."":(Ljava/lang/String;)V
13: invokespecial #6 // Method java/io/BufferedReader."":(Ljava/io/Reader;)V
16: astore_0
17: aconst_null
18: astore_1
19: aload_1
20: invokeinterface #7, 1 // InterfaceMethod java/sql/Connection.createStatement:()Ljava/sql/Statement;
25: astore_2
26: goto 42
29: astore_0
30: aload_0
31: invokevirtual #11 // Method java/io/IOException.printStackTrace:()V
34: goto 42
37: astore_0
38: aload_0
39: invokevirtual #12 // Method java/sql/SQLException.printStackTrace:()V
42: return
Exception table:
from to target type
0 26 29 Class java/io/IOException
0 26 37 Class java/sql/SQLException


switch那里生成的字节码不太明显看出来优化在哪里,这个很明显。首先,字节码长度变少 其次,从最后可以看出,target type都指向29行,两个catch会指向不同的行~

2、用更包容性的类型检查来重新抛出异常

在方法的声明上,使用throws语句时,你可以指定更加详细的异常类型。




Java代码
static class FirstException extends Exception { }
static class SecondException extends Exception { }

public void rethrowException(String exceptionName) throws Exception {
try {
if (exceptionName.equals("First")) {
throw new FirstException();
} else {
throw new SecondException();
}
} catch (Exception e) {
throw e;
}
}


这个例子,try块中只能抛出两种异常,但是因为catch里的类型是 Exception,在java SE7以前的版本中,在方法声明中throws 只能写Exception,但是在java SE7及以后的版本中,可以在throws后面写 FirstException和SecondException——编译器能判断出throw e语句抛出的异常一定来自try块,并且try块只能抛出FirstException和SecondException。



Java代码
public static void reThrowException(String exceptionName)
throws FirstException, SecondException{
try {
if ("first".equals(exceptionName))
throw new FirstException();
else
throw new SecondException();
} catch (Exception e) {
throw e;
}
}



所以尽管catch里的异常类型是Exception,编译器仍然能够知道它是FirstException和 SecondException的实例。怎么样,编译器变

得更智能了吧。

但是,如果在catch里对异常重新赋值了,在方法的throws后无法再向上面那样写成FirstException和SecondException了,而需要写成 Exception。

具体来说,在Java SE 7及以后版本中,当你在catch语句里声明了一个或多个异常类型,并且在catch块里重新抛出了这些异常,编译器根据下面几个条件来去核实异常的类型:

- Try块里抛出它
- 前面没有catch块处理它
- 它是catch里一个异常类型的父类或子类。


特性6:创建泛型对象时类型推断

只要编译器可以从上下文中推断出类型参数,你就可以用一对空着的尖括号<>来代替泛型参数。这对括号私下被称为菱形(diamond)。

在Java SE 7之前,你声明泛型对象时要这样



Java代码
List list = new ArrayList();


而在Java SE7以后,你可以这样



Java代码
List list = new ArrayList<>();


因为编译器可以从前面(List)推断出推断出类型参数,所以后面的ArrayList之后可以不用写泛型参数了,只用一对空着的尖括号就行。当然,你必须带着”菱形”<>,否则会有警告的。

Java SE7 只支持有限的类型推断:只有构造器的参数化类型在上下文中被显著的声明了,你才可以使用类型推断,否则不行。



Java代码
List list = new ArrayList<>();
list.add("A");

//这个不行
list.addAll(new ArrayList<>());

// 这个可以
List list2 = new ArrayList<>();
list.addAll(list2);


注意:菱形<>主要用在变量声明里。

类里也可以使用类型推断



准备返京,未完待续~


Java 7 从呼之欲出到千呼万唤使出来,经历了好几年,期间sun也易主,真是不容易。

不过想要马上大规模的使用还不现实,Java 6从推出到大规模的使用花了两三年的时间吧(这里我不太清楚)甚至更久,到现在还有好多大公司使用 java5或4呢,所以这也是我为什么把java 7装到虚拟机上的缘故,毕竟商业的东西,还是以稳定为主。
以上介绍了些皮毛,未来还要靠大家自己多多努力,争取两年后,java 7正式商用了,大家也能对java 7掌握的更熟练写,更好的应用,提高自己的工作效率。

相关文档
最新文档