java 8已于2014年3月18日正式发布了,新版本带来了诸多改进,包括Lambda表达式、Streams、日期时间API等等。【ITjob】负责java培训的老师就带你领略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变化和稳定性记录
VM基础改进:
JEP 142:减少指定字段上的缓存争用
VM垃圾回收(vm/gc)改进:
JEP 122:移除Permanent Generation(永久代)
JEP 173:移除一些很少使用的垃圾回收器组合
VM运行时(vm/rt)改进:
JEP 136:提供更多的验证错误信息
JEP 147:减少类元数据封装
JEP 148:支持创建小型虚拟机(3M以下)
JEP 171:添加3个内存有序化的内联函数
核心基础(core)改进:
JEP 153:命令行启动JavaFX应用
核心lang(core/lang)改进:
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注释内容
核心库(core/libs)改进:
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碰撞
核心i18n(core/i18n)改进:
JEP 127:改进了本地数据封装,采用Unicode CLDR数据
JEP 128:BCP 47局部匹配
JEP 133:Unicode 6.2
核心net(core/net)改进:
JEP 184:HTTP URL访问权限
核心安全(core/sec)改进:
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密钥库
web/jaxp改进:
JEP 185:JAXP 1.5(限制获取外部资源)
深圳java培训老师带领你一步一步地认识这门语言的新特性。通过简单明了的代码示例,你将会学习到如何使用默认接口方法,Lambda表达式,方法引用和重复注解。看完这篇教程后,你还将对最新推出的API有一定的了解,例如:流控制,函数式接口,map扩展和新的时间日期API等等。
Lambda表达式
让我们从最简单的例子开始,来学习如何对一个string列表进行排序。我们首先使用Java 8之前的方法来实现:
Java代码
List names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
静态工具方法Collections.sort接受一个list,和一个Comparator接口作为输入参数,Comparator的实现类可以对输入的list中的元素进行比
较。通常情况下,你可以直接用创建匿名Comparator对象,并把它作为参数传递给sort方法。
除了创建匿名对象以外,Java 8 还提供了一种更简洁的方式,Lambda表达式。
Java代码
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
你可以看到,这段代码就比之前的更加简短和易读。但是,它还可以更加简短:
Java代码
Collections.sort(names, (String a, String b) -> b.compareTo(a));
只要一行代码,包含了方法体。你甚至可以连大括号对{}和return关键字都省略不要。不过这还不是最短的写法:
Java代码
Collections.sort(names, (a, b) -> b.compareTo(a));
Java编译器能够自动识别参数的类型,所以你就可以省略掉类型不写。让我们再深入地研究一下lambda表达式的威力吧。
函数式接口
Lambda表达式如何匹配Java的类型系统?每一个lambda都能够通过一个特定的接口,与一个给定的类型进行匹配。一个所谓的函数式接口必须要有且仅有一个抽象方法声明。每个与之对应的lambda表达式必须要与抽象方法的声明相匹配。由于默认方法不是抽象的,因此你可以在你的函数式接口里任意添加默认方法。
任意只包含一个抽象方法的接口,我们都可以用来做成lambda表达式。为了让你定义的接口满足要求,你应当在接口前加上@FunctionalInterface 标注。编译器会注意到这个标注,如果你的接口中定义了第二个抽象方法的话,编译器会抛出异常。
举例:
Java代码
@FunctionalInterface
interface Converter {
T convert(F from);
}
Converter converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123
注意,如果你不写@FunctionalInterface 标注,程序也是正确的。
方法和构造函数引用
上面的代码实例可以通过静态方法引用,使之更加简洁:
Java代码
Converter converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted); // 123
Java 8 允许你通过::关键字获取方法或者构造函数的的引用。上面的例子就演示了如何引用一个静态方法。而且,我们还可以对一个对象的方
法进行引用:
Java代码
class Something {
String startsWith(String s) {
return String.valueOf(s.charAt(0));
}
}
Something something = new Something();
Converter converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted); // "J"
让我们看看如何使用::关键字引用构造函数。首先我们定义一个示例bean,包含不同的构造方法:
Java代码
class Person {
String firstName;
String lastName;
Person() {}
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
接下来,我们定义一个person工厂接口,用来创建新的person对象:
Java代码
interface PersonFactory
{
P create(String firstName, String lastName);
}
然后我们通过构造函数引用来把所有东西拼到一起,而不是像以前一样,通过手动实现一个工厂来这么做。
Java代码
PersonFactory personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");
我们通过Person::new来创建一个Person类构造函数的引用。Java编译器会自动地选择合适的构造函数来匹配PersonFactory.create函数的签名,并选择正确的构造函数形式。
Lambda的范围
对于lambdab表达式外部的变量,其访问权限的粒度与匿名对象的方式非常类似。你能够访问局部对应的外部区域的局部final变量,以及成员变量和静态变量。
访问局部变量
我们可以访问lambda表达式外部的final局部变量:
Java代码
final int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3
但是与匿名对象不同的是,变量num并不需要一定是final。下面的代码依然是合法的:
Java代码
int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3
然而,num在编译的时候被隐式地当做final变量来处理。下面的代码就不合法:
Java代码
int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
num = 3;
在lambda表达式内部企图改变num的值也是不允许的。
访问成员变量和静态变量
与局部变量不同,我们在lambda表达式的内部能获取到对成员变量或静态变量的读写权。这种访问行为在匿名对象里是非常典型的。
Java代码
class Lambda4 {
static int outerStaticNum;
int outerNum;
void testScopes() {
Converter stringConverter1 = (from) -> {
outerNum = 23;
return String.valueOf(from);
};
Converter stringConverter2 = (from) -> {
outerStaticNum = 72;
return String.valueOf(from);
};
}
}
访问默认接口方法
还记得第一节里面formula的那个例子么? 接口Formula定义了一个默认的方法sqrt,该方法能够访问formula所有的对象实例,包括匿名对象
。这个对lambda表达式来讲则无效。
默认方法无法在lambda表达式内部被访问。因此下面的代码是无法通过编译的:
Java代码
Formula formula = (a) -> sqrt( a * 100);
内置函数式接口
JDK 1.8 API中包含了很多内置的函数式接口。有些是在以前版本的Java中大家耳熟能详的,例如Comparator接口,或者Runnable接口。对这些现成的接口进行实现,可以通过@FunctionalInterface 标注来启用Lambda功能支持。
此外,Java 8 API 还提供了很多新的函数式接口,来降低程序员的工作负担。有些新的接口已经在Google Guava库中很有名了。如果你对这些库很熟的话,你甚至闭上眼睛都能够想到,这些接口在类库的实现过程中起了多么大的作用。
Predicates
Predicate是一个布尔类型的函数,该函数只有一个输入参数。Predicate接口包含了多种默认方法,用于处理复杂的逻辑动词(and, or,
negate):
Java代码
Predicate predicate = (s) -> s.length() > 0;
predicate.test("foo"); // true
predicate.negate().test("foo"); // false
Predicate nonNull = Objects::nonNull;
Predicate isNull = Objects::isNull;
Predicate isEmpty = String::isEmpty;
Predicate isNotEmpty = isEmpty.negate();
Functions
Function接口接收一个参数,并返回单一的结果。默认方法可以将多个函数串在一起(compse, andThen):
Java代码
Function toInteger = Integer::valueOf;
Function backToString = toInteger.andThen(String::valueOf);
backToString.apply("123"); // "123"
Suppliers
Supplier接口产生一个给定类型的结果。与Function不同的是,Supplier没有输入参数。
Java代码
Supplier personSupplier = Person::new;
personSupplier.get(); // new Person
Consumers
Consumer代表了在一个输入参数上需要进行的操作。
Java代码
Consumer greeter = (p) -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker"));
Comparators
Comparator接口在早期的Java版本中非常著名。Java 8 为这个接口添加了不同的默认方法。
Java代码
Comparator comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);
Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");
comparator.compare(p1, p2); // > 0
comparator.reversed().compare(p1, p2); // < 0
(文章来源:http://www.mfqyw.com/)