HTTPD  • • •  First real Python Program       all posts in Archive

What's new in Java SE7

SUN这个悲剧破产过程,让一切都变得拖拖拉拉,混乱不堪,从2010年说到2011年,终于 Java7 来了。好死不死的 JAVA 也该加把火了。Oracle 是不是个好 “东家”,不是一朝一夕能够看清楚的。刚发布就出了HotSpot Loop optimizations的BUG,把JVM搞崩溃。不过还算发现即时,当然现在的 7  可能还不是开发的最佳选择,但是 Java7 到底有什么新鲜的玩意儿呢?

Switch 增加了对字符串的支持

	String str = "abc";
	switch (str) {
	case "abc":
		System.out.println("yes");
		break;
	case "efg":
		System.out.println("no");
		break;
	default:
		break;
	}

这个对代码的影响还是很大的。有很多 ELSE IF 都能得到简化。

Try-with-Resources

先看一段1.6 版本里的写法:

	File file = new File("test.xml");
	InputStream is = null;

	try{
		is = new FileInputStream(file);
	}catch(FileNotFoundException e){
		System.err.println("Missing file " + file.getAbsolutePath());
	}catch(IOException e){
	        System.err.println("Missing file " + file.getAbsolutePath());
        }finally{
		if(is != null){
			is.close();
		}
	}

Java7 里我们怎么做呢?

	File file = new File("D://test.txt");
	try(FileInputStream is = new FileInputStream(file)){
		//do something
	}catch(IOException | NullPointerException e){
		System.err.println("Missing file " + file.getAbsolutePath());
	}

Try-with-resources 里的资源能够自动释放了,不用繁琐的写 finally 了。另外 “|” 能够简化无聊的一大段拷贝代码。Sonar Check 应该很乐于看到这样的代码简化吧。

Rethrowing Exceptions with More Inclusive Type Checking

在1.6 版本里,我们在方法的 throws 里面无法丢出 FirstException 和 SecondException , 如果你尝试这么做,会得到这样的错误信息 "unreported exception Exception; must be caught or declared to be thrown"。 因为catch块里捕获了 Exception。

	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;
		}
	}

Java 7 里面,你可以无视 catch 块直接抛出 FirstException 和 SecondException:

	public void rethrowException(String exceptionName) throws FirstException,
			SecondException {
		try {
			// ...
		} catch (Exception e) {
			throw e;
		}
	}

Java7 的编译器,可以辨别出 “e” 是FirstException 或者 SecondException的实例。在7和以后的版本中,当你再catch块中捕获一个或者多个异常类型,并重新抛出时,编译器会检查这些异常的类型是否满足下面的要求:

  • Try 块能够抛出这些异常
  • 没有其他更优先的catch块已经能捕获它
  • 它是某一个catch块参数的 subtype 或者 supertype

拿这里来说,能够抛出 FirstException 和 SecondException 的原因是他们是 Exception 的 subtype.

 

改善了针对泛型实例创建

可以将:

Map<String, List<String>> anagrams = new HashMap<String, List<String>>();

简化成:

Map<String, List<String>> anagrams = new HashMap<>();

 

数字增加了二进制表示和下划线分隔符

先来看看二进制表示:

byte b = 0b001_00001;
short s = 0b001001001001;
int i = 0b001001001001001;

再来看看下划线:

int i = 123_3457;
long l = 123_2983L;
long maxLong = 0x7fff_ffff_ffff_ffffL; // 二进制表示

毫无疑问,下划线能够增强可读性,但是有几个不适用的地方:

  • 不能用在数字的开头
  • 不能用在小数点的左边或者右边
  • 不能用在Long或者Float型的后缀符F或者L的左边或者右边
  • 不能拆散二进制八进制十六进制数字 比如原本的0X被拆成0_X

 

两个主要的新API

第一个 是JSR 203,针对文件系统访问、可扩展异步I/O操作、多播数据包、Socket通道绑定和配置添加了新的API。企业开发者特别感兴趣的是增加了真正的异步I/O API,这对需要跨多连接的低延时、高吞吐的高端服务器应用程序来说尤为重要。JSR 203还为Java添加了一个真的文件系统API,提供了对某些OS特定功能的支持。例如,你可以在支持符号链接的系统中创建符号链接。但这一特性也备受争议,虽然JSR 203提供了可运行于所有平台、支持平台特定特性的通用API,但它并非严格意义上的“一次编写到处运行”。

第二个 新API是Fork/Join框架(JSR 166的一部分),起初是计划放在Java 5里的。它为开发者提供了一种机制,可以将问题拆解为多个任务,在任意数量的处理器核心上并行执行。

 

新的字节码指令 : InvokeDynamic

为了支持越来越多在 JVM 上跑的动态语言。Java SE 7使用了InvokeDynamic关键字来标记Java诞生后的首个新字节码指令。InvokeDynamic添加了一种新的调用模式和链接模式,可以通过编程支持用户定制的规范。特别是在缺乏静态类型信息的方法调用中,它能支持高效、灵活的方法执行,这大幅改善了动态语言的性能,例如运行于JVM之上的JRuby和Jython。

新的 invokedynamic 字节码指令的语法与 invokeinterface 指令类似:

invokedynamic < method-specification> < n>

invokeinterface 字节码指令差不多是这样:

invokedynamic #10;
//DynamicMethod java/lang/Object.lessThan:(Ljava/lang/Object;)

invokedynamic 的区别就在于它的 < method-specification> 只需指定方法名称,对描述符的唯一要求是它应引用非空对象。invokedynamic 字节码指令运行动态语言的实现器(implementer)将方法调用编译为字节码,而不必指定目标的类型,该目标包含了方法、调用的返回类型或方法参数类型。这些类型对于执行指令的 JVM 不必是已知的。

问题来了,如果未提供接收器的类型,JVM 该如何找到该方法? 答案在于,JSR 292 还包含了一个新的动态类型语言的连接机制。JVM 使用新的连接机制获取所需的方法。

新的动态连接机制:方法句柄(method handle)

JDK 7 包含了新包,java.dyn,其中包含了与在 Java 平台中动态语言支持相关的类。其中一个类为 MethodHandle.方法句柄是类型 java.dyn.MethodHandle 的一个简单对象,该对象包含一个 JVM 方法的匿名引用。

新连接机制还包含一个bootstrap 方法,它是一个方法句柄,决定了call site 调用的目标方法。Call site 是调用指令的实例,这里它就是 invokedynamic 字节码指令的实例。包含 invokedynamic 指令的每个类都必须指定 bootstrap 方法。

JVM 第一次遇到具有接收器和参数的 invokedynamic 字节码时,它调用 bootstrap方法。(调用语言支持的方法,可以使用术语 up-call 来描述。)

bootstrap方法反过来选择相应的目标方法句柄。然后 JVM 将该方法句柄引用的方法与 invokedynamic 字节码关联起来。JVM 下次遇到具有相同接收器和参数的 invokedynamic 字节码时,它将立即调用之前所选的方法。

方法句柄相当简单,仅包含一个描述特定类型的 type toke。此外,方法句柄隐式地包含一个与其关联的 invoke 方法。要调用方法句柄,你需要调用它的 invoke 方法,与调用对象方法类似,即 MethodHandle.invoke(……)。由于每个方法句柄都具有其自身的类型,因此,它只接受那个类型的 invoke 调用。如果调用的类型与方法句柄的类型不匹配,方法句柄将返回异常。

总之,方法句柄提供了一种连接机制,它能够让 JVM 根据 invokedynamic 字节码指令调用正确的方法。但 JVM 遇到 invokedynamic 字节码时,它将使用方法句柄获得所需的方法。

请注意,相对于映射调用,方法句柄提供了一种更好的方式,来满足方法调用的字节码要求。相较而言,方法句柄提供了一种命名和连接方法的方式,而无需考虑方法类型或位置,而且这种方式具有完善的类型安全和本地的执行速度。

其他

新的网络和安全特性,对国际化的扩展支持中还包括了Unicode 6.0支持,等