Java 7新特性总结 - Coin项目新语言特性

来源:互联网 发布:淘宝买电子版资料 编辑:程序博客网 时间:2024/05/22 15:52

Coin项目

OpenJDK中的Coin项目的目的是维护对Java语言所做的语法增强。
在Coin项目开始之初,曾经广泛地向社区征求提议。在短短的一个月时间内就收到了近70条提议。最后有9条提议被列入考虑之中。在这9条提议中,有6条成为Java 7的一部分,剩下的2条提议会在Java 8中重新考虑,还有1条提议被移到其他项目中实现。

1. 在switch语句中使用字符串

在Java 7之前,switch语句中的条件表达式的类型只能是与整数类型兼容的类型,包括基本类型char、byte、short和int,与这些基本类型对应的封装类Character、Byte、Short和Integer,还有枚举类型。
根据switch语句的语法要求,其case子句的值是不能重复的。这个要求对字符串类型的条件表达式同样适用。不过对于字符串来说,这种重复值的检查还有一个特殊之处,那就是Java代码中的字符串可以包含Unicode转义字符。
实现:原来用在switch语句中的字符串被替换成了对应的哈希值,而case子句的值也被换成了原来字符串常量的哈希值。经过这样的转换,Java虚拟机所看到的仍然是与整数类型兼容的类型。在这里值得注意的是,在case子句对应的语句块中仍然需要使用String的equals方法来进行字符串比较。这是因为哈希函数在映射的时候可能存在冲突,多个字符串的哈希值可能是一样的。

2. 枚举类型

如果代码中有多个地方使用switch语句来枚举字符串,就考虑用枚举类型进行替换。

3.数值字面量的改进

二进制整数字面量

在Java 7之前,所支持的进制包括十进制、八进制和十六进制。十进制是默认使用的进制。八进制是用在整数字面量之前添加“0”来表示的,而十六进制则是用在整数字面量之前添加“0x”或“0X”来表示的。Java 7中增加了一种可以在字面量中使用的进制,即二进制。二进制整数字面量是通过在数字前面添加“0b”或“0B”来表示的

在数值字面量中使用下划线

比如数字500000,我们通常会写成500,000,即每三位数字用逗号分隔。利用这种方式就可以很快知道数值的大小。这种做法的理念被加入到了Java 7中,不过用的不是逗号,而是下划线“_”。
下划线只能出现在数字中间,也就是说前后都必须是数字。所以“100”、“120”、“0b_101”、“0x_da0”这样的使用方式都是非法的,无法通过编译。

4. 异常优化

异常的基础知识

受检异常和非受检异常:非受检异常指的是java.lang.RuntimeException和java.lang.Error类及其子类,所有其他的异常类都称为受检异常。两种类型的异常在作用上并没有差别,唯一的差别就在于使用受检异常时的合法性要在编译时刻由编译器来检查。正因为如此,受检异常在使用的时候需要比非受检异常更多的代码来避免编译错误。

目前的主流意见是,最好优先使用非受检异常。
异常声明是API的一部分:在一个公开方法的声明中使用throws关键词来声明其可能抛出的异常的时候,这些异常就成为这个公开方法的一部分,属于开放API。如果公开方法声明了会抛出一个受检异常,那么这个API的使用者肯定已经使用了try-catch-finally来处理这个异常。如果在后面的版本更新中,发现该API抛出这个异常是不合适的,也不能直接把这个异常的声明删除。因为这样会造成之前的API使用者的代码无法通过编译。但是对于一个方法会抛出的非受检异常,也需要在文档中进行说明。
决定是否在某个方法中处理一个异常需要判断从异常中恢复的方式是否合理。比如一个方法要从文件中读取配置信息,进行文件操作时可能抛出IOException。当出现异常的时候,如果可以采取的恢复措施是使用默认值,那么在这个方法中处理IOException就是合理的。而在同样的场景中,如果某些配置项没有合法的默认值,必须要手工设置一个值,那么读取文件时出现的IOException就不应该在这个方法中处理。
消失的异常:在try语句块中抛出了异常,在控制权转移到调用栈上一层代码之前,finally语句块中的语句也会执行。但是finally语句块在执行的过程中,也可能会抛出异常。如果finally语句块也抛出了异常,那么这个异常会往上传递,而之前try语句块中的那个异常就丢失了。
对这种问题的解决办法一般有两种,一种是抛出try语句块中产生的原始异常,忽略在finally语句块中产生的异常。这么做的出发点是try语句块中的异常才是问题的根源。另外一种是把产生的异常都记录下来。这么做的好处是不会丢失任何异常。在Java 7之前,这种做法需要实现自己的异常类,而在Java 7中,已经对Throwable类进行了修改以支持这种情况。
使用addSuppressed方法记录异常的示例

public class ReadFile {      public void read(String filename) throws IOException {          FileInputStream input = null;          IOException readException = null;          try {              input = new FileInputStream(filename);          } catch (IOException ex) {              readException = ex;          } finally {              if (input != null) {                  try {                      input.close();                  } catch (IOException ex) {                      if (readException != null) {                          readException.addSuppressed(ex);                      }                      else {                          readException = ex;                      }                  }              }              if (readException != null) {                  throw readException;              }          }      }  } 

5. try-with-resources

如果资源初始化时或try语句中出现异常,而释放资源的操作正常执行,try语句中的异常会被抛出;如果try语句和释放资源都出现了异常,那么最终抛出的异常是try语句中出现的异常,在释放资源时出现的异常会作为被抑制的异常添加进去
够被try语句所管理的资源需要满足一个条件,那就是其Java类要实现java.lang.AutoCloseable接口,否则会出现编译错误。

public class CustomResource implements AutoCloseable {      public void close() throws Exception {          System.out.println("进行资源释放。");      }      public void useCustomResource() throws Exception {          try (CustomResource resource = new CustomResource())  {              System.out.println("使用资源。");          }      }  }

使用try-with-resources语句管理两个资源的示例:

public class MultipleResourcesUsage {      public void copyFile(String fromPath, String toPath) throws IOException {          try (InputStream input = new FileInputStream(fromPath);                  OutputStream output = new FileOutputStream(toPath)) {              byte[] buffer = new byte[8192];              int len = -1;              while ((len = input.read(buffer)) != -1) {                  output.write(buffer, 0, len);              }          }      }  } 

6. 优化变长参数的方法调用

在Java 7之前,如果可变长度的参数与泛型一起使用会遇到一个麻烦,就是编译器产生的警告过多。
使用@SafeVarargs注解抑制编译器警告的示例

@SafeVarargs  public static <T> T useVarargs(T... args) {      return args.length > 0 ? args[0] : null;  } 

@SafeVarargs注解只能用在参数长度可变的方法或构造方法上,且方法必须声明为static或final,否则会出现编译错误。一个方法使用@SafeVarargs注解的前提是,开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题。

0 0