经过2年半的努力、屡次的延期和9个里程碑版本,甲骨文的Java开发团队终于发布了Java 8正式版本。
Java 8版本最大的改进就是Lambda表达式,其目的是使Java更易于为多核处理器编写代码;其次,新加入的Nashorn引擎也使得Java程序可以和JavaScript代码互操作;再者,新的日期时间API、GC改进、并发改进也相当令人期待。
另外,原本要加入Java 8的Jigsaw项目(标准模块系统)由于开发时间关系,被推迟到了Java 9中,不过Java 8已经在朝着这个方向努力了。
Java 8的所有新特性及改进包括(JEP全称为JDK Enhancement Proposal,JDK改进建议):
语言改进:
- JEP 126:Lambda表达式 & 虚拟扩展方法
- JEP 138:基于Autoconf的构建系统
- JEP 160:针对Method Handles的Lambda形式的表征
- JEP 161:简洁的配置文件
- JEP 162:为模块化做准备
- JEP 164:利用CPU指令来改善AES加密的性能
- JEP 174:Nashorn引擎,允许在Java程序中嵌入JS代码
- JEP 176:自动检测识别Caller-Sensitive方法
- JEP 179:JDK API变化和稳定性记录
- JEP 142:减少指定字段上的缓存争用
VM运行时(vm/rt)改进:
核心基础(core)改进:
- JEP 153:命令行启动JavaFX应用
- JEP 101:目标类型推断
- JEP 104:Java类型注解
- JEP 105:DocTree API
- JEP 106:在javax.tools中添加Javadoc
- JEP 117:移除APT(Annotation-Processing Tool)
- JEP 118:运行过程中可访问参数名
- JEP 120:重复注解
- JEP 139:增强了javac,以改善构建速度
- JEP 172:DocLint工具,用来检查Javadoc注释内容
- JEP 103:并行数组排序
- JEP 107:集合数据批量操作
- JEP 109:增强的包含Lambda的核心库
- JEP 112:改进了字符集的实现
- JEP 119:Core Reflection提供的javax.lang.model实现
- JEP 135:Base64编解码
- JEP 149:减少了核心库的内存占用
- JEP 150:日期时间API
- JEP 155:改进对并发的支持
- JEP 170:JDBC 4.2
- JEP 177:java.text.DecimalFormat.format优化
- JEP 178:静态链接的JNI库
- JEP 180:使用平衡树处理频繁的HashMap碰撞
核心net(core/net)改进:
- JEP 184:HTTP URL访问权限
- JEP 113:MS-SFU Kerberos 5扩展
- JEP 114:TLS Server Name Indication(SNI)扩展
- JEP 115:AEAD密码套件
- JEP 121:更强的口令加密系统算法
- JEP 123:可配置的安全随机数生成方法
- JEP 124:增强了证书撤回检测API
- JEP 129:NSA Suite B加密算法实现
- JEP 130:SHA-224消息摘要算法实现
- JEP 131:针对64位Windows的SunPKCS11加密提供程序
- JEP 140:特权限制
- JEP 166:彻底检修JKS-JCEKS-PKCS12密钥库
- JEP 185:JAXP 1.5(限制获取外部资源)
Java8带有Lambda表达式的预览版的JDK已经放出来了(地址在最下面),新特性有以下四个: 1.Lambda表达式(或称之为“闭包”或者“匿名函数”) 2.扩展的目标类型 3.方法和构造器引用 4.接口默认方法 本文先介绍一下很值得期待的Lambda表达式,lambda表达式,等同于大多说动态语言中常见的闭包、匿名函数的概念。其实这个概念并不是多么新鲜的技术,在C语言中的概念类似于一个函数指针,这个指针可以作为一个参数传递到另外一个函数中。 |
|
由于Java是相对较为面向对象的语言,一个Java对象中可以包含属性和方法(函数),方法(函数)不能孤立于对象单独存在。这样就产生了一个问题,有时候需要把一个方法(函数)作为参数传到另外一个方法中的时候(比如回调功能),就需要创建一个包含这个方法的接口,传递的时候传递这个接口的实现类,一般是用匿名内部类的方式来。如下面代码,首先创建一个Runnable的接口,在构造Thread时,创建一个Runnable的匿名内部类作为参数:
- newThread(newRunnable(){
- publicvoidrun(){
- System.out.println("hello");
- }
- }).start();
类似这种情况的还有swing中button等控件的监听器,如下面代码所示,创建该接口的一个匿名内部类实例作为参数传递到button的addActionListener方法中。
- publicinterfaceActionListener{
- voidactionPerformed(ActionEvente);
- }
- button.addActionListener(newActionListener(){
- publicvoidactionPerformed(ActionEvente){
- ui.dazzle(e.getModifiers());
- }
- });
这样的代码的缺点是有代码笨重,可读性差,不能引用外面的非final的变量等。lambda表达式就是为了解决这类问题而诞生的。
在介绍Java8中的Lambda表达式之前,首先介绍一个概念叫“函数式接口”(functional interfaces)。对于任意一个Java接口,如果接口中只定义了唯一一个方法,那么这个接口就称之为“函数式接口”。比如JDK中的ActionListener、Runnable、Comparator等接口。
先来看一下Java8中的lambda表达式的使用示例:
创建一个线程:
- newThread(()->{System.out.println("hello");}).start();
可以看到这段代码比上面创建线程的代码精简了很多,也有很好的可读性。
() -> {System.out.println("hello");} 就是传说中的lambda表达式,等同于上面的new Runnable(), lambda大体分为3部分:
1.最前面的部分是一对括号,里面是参数,这里无参数,就是一对空括号
2.中间的是 -> ,用来分割参数和body部分
3.是body部分,可以是一个表达式或者一个语句块。如果是一个表达式,表达式的值会被作为返回值返回;如果是语句块,需要用return语句指定返回值。如下面这个lambda表达式接受一个整形的参数a,返回a的平方
- (inta)->a^2
等同于
- (inta)->{returna^2;}
继续看更多的例子:
- (intx,inty)->x+y
- ()->42
- (Strings)->{System.out.println(s);}
创建一个FileFilter,文件过滤器:
- FileFilterjava=(Filef)->f.getName().endsWith(".java")
创建一个线程:
- newThread(()->{
- //dosthhere...
- }).start()
创建一个Callable:
- Callable<String>c=()->"done";
创建一个String的比较器:
- Comparator<String>c=(s1,s2)->s1.compareToIgnoreCase(s2);
而且lambda表达式可以赋值给一个变量:
- Comparator<String>c;
- c=(Strings1,Strings2)->s1.compareToIgnoreCase(s2);
还可以作为方法的返回值:
- publicRunnabletoDoLater(){
- return()->{
- System.out.println("later");
- };
- }
从上面可以看到,一个lambda表达式被作为一个接口类型对待,具体对应哪个接口,编译器会根据上下文环境推断出来,如下面的lambda表达式就表示一个ActionListener.
- ActionListenerl=(ActionEvente)->ui.dazzle(e.getModifiers());
这有可能会造成一个表达式在不同的上下文中被作为不同的类型,如下面的这种情况,尽管两个表达式是相同的,上面的表达式被推断为Callable的类型,下面的会被推断为PrivilegedAction类型。
- Callable<String>c=()->"done";
- PrivilegedAction<String>a=()->"done";
那么编译器是根据哪些因为决定一个表达式的类型呢?
如果一个表达式被推断为是T类型的,需要满足以下4个条件:
1.T是函数式接口类型(只声明唯一一个方法)
2.表达式和T中声明的方法的参数个数一致,参数类型也一致
3.表达式和T中声明的方法的返回值类型一致
4.表达式和T中声明的方法抛出的异常一致
有了这个准则,上面的疑问就迎刃而解了
函数式接口。函数式接口是只定义了一个抽象方法的接口。Java 8引入了FunctionalInterface注解来表明一个接口打算成为一个函数式接口。例如,java.lang.Runnable就是一个函数式接口。
Lambda。函数式接口的重要属性是:我们能够使用lambda实例化它们,Lambda表达式让你能够将函数作为方法参数,或者将代码作为数据对待。
方法引用。方法引用是简洁的Lambda表达式,能够用于已经拥有名称的方法。下面是一些方法引用的例子,右边是同样效果的Lambda表达式。
java.util.stream。新的 java.util.stream包提供了对值流进行函数式操作的类。
改进了泛型推断。这提升了Java编译器推断泛型和在泛型方法调用中减少显式类型参数的能力。
java.time。新的日期/时间API包含在 java.time包中。所有的类都是不可变且线程安全的。日期和时间类型包括Instant、LocalDate、LocalTime、LocalDateTime和ZonedDateTime。除了日期和时间之外,还有Duration和Period类型。另外,值类型包括Month、DayOfWeek、Year、 Month、YearMonth、MonthDay、OffsetTime和OffsetDateTime。这些新的日期/时间类大部分JDBC都支持。
当然,以上只是一小部分新特性,关于Java 8的相关信息,请点此查看。
Jigsaw项目被推迟到Java SE 9
“对于Java开发者来说,Java 8意味着一次重大的转变。”JFrog公司CTO Yoav Landman表示,“JDK 8加入了Lambda表达式以及方法引用,这会让程序变得更加简单。”
IDC分析师Al Hilwa也表示,加入Lambda是Java的一次重要变化,这对于并行编程来说将非常有益。“虽然给编程语言带来了很大的影响,但Lambda仅仅是增加并行化编程能力的一部分。”
JDK 8原定于去年9月发布,但由于安全问题,Oracle推迟到了今年3月份。此外,原本计划加入的Project Jigsaw,也推迟到了Java SE 9上,这让很多Java开发者失望不已。
此外, 国外媒体也针对JDK 8进行了一项调查,主要面向Java中间件厂商。调查结果显示,有29%的公司计划六个月内升级到最新版本;有25%公司会在十二个月内完成升级;有32%的公司还未对新版本进行评估;同时,也有22%的企业还在使用在2006年发布的Java SE 6。