jdk8的更新内容
http://openjdk.java.net/projects/jdk8/
JCP(Java Community Process) :是一个开放的国际组织,主要由Java开发者以及被授权者组成,职能是发展和更新。
JEP(JDK Enhancement Proposals):jdk 改进提案,每当需要有新的设想时候,JEP可以在JCP(java community Process)之前或者同时提出非正式的规范(specification),被正式认可的JEP正式写进JDK的发展路线图并分配版本号。
JSR(Java Specification Requests):java规范提案,新特性的规范出现在这一阶段,是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。请求可以来自于小组/项目、JEP、JCP成员或者java社区(community)成员的提案,每个java版本都由相应的JSR支持。
一、Lambda表达式
Java是一门面向对象编程语言。面向对象编程语言和函数式编程语言中的基本元素(Basic Values)都可以动态封装程序行为:面向对象编程语言使用带有方法的对象封装行为,函数式编程语言使用函数封装行为。但这个相同点并不明显,因为Java的对象往往比较“重量级”:实例化一个类型往往会涉及不同的类,并需要初始化类里的字段和方法。
不过有些Java对象只是对单个函数的封装。例如下面这个典型用例:Java API中定义了一个接口(一般被称为回调接口),用户通过提供这个接口的实例来传入指定行为,例如:
public interface ActionListener {
void actionPerformed(ActionEvent e);
}
这里并不需要专门定义一个类来实现ActionListener接口,因为它只会在调用处被使用一次。用户一般会使用匿名类型把行为内联(inline):
button.addActionListener(new ActionListener) {
public void actionPerformed(ActionEvent e) {
ui.dazzle(e.getModifiers());
}
}
很多库都依赖于上面的模式。对于并行API更是如此,因为我们需要把待执行的代码提供给并行API,并行编程是一个非常值得研究的领域,因为在这里摩尔定律得到了重生:尽管我们没有更快的CPU核心(core),但是我们有更多的CPU核心。而串行API就只能使用有限的计算能力。
随着回调模式和函数式编程风格的日益流行,我们需要在Java中提供一种尽可能轻量级的将代码封装为数据(Model code as data)的方法。匿名内部类并不是一个好的选择,因为:
上面的多数问题均在Java SE 8中得以解决:
不过,Java SE 8的目标并非解决所有上述问题。因此捕获可变变量(问题4)和非局部控制流(问题5)并不在Java SE 8的范畴之内。(尽管我们可能会在未来提供对这些特性的支持)
匿名类型最大的问题就在于其冗余的语法。有人戏称匿名类型导致了“高度问题”(height problem):比如前面ActionListener的例子里的五行代码中仅有一行在做实际工作。
lambda表达式是匿名方法,它提供了轻量级的语法,从而解决了匿名内部类带来的“高度问题”。
2.1、lambda表达式的语法
Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为“->” ,该操作符被称为Lambda 操作符或剪头操作符。它将Lambda 分为两个部分:
左侧:指定了Lambda 表达式需要的所有参数
右侧:指定了Lambda 体,即Lambda 表达式要执行的功能。
2.2、无参构造函数
无返回值,lambda体只有一条语句
// jdk 1.7及以前
Runnable r1 = new Runnable() {
public void run() {
System.out.println("hello word")
}
};
// jdk 1.8
Runnable r = ()-> System.out.println("hello word");
2.3、只有一个参数的构造函数
无返回值,lambda体只有一条语句
//jdk 1.7及以前
Consumer consumer = new Consumer() {
public void accept(String s) {
System.out.println(s);
}
};
// jdk 1.8
Consumer consumer1 = (s)-> System.out.println(s);
2.4、只有一个参数的构造函数,小括号可以省略
//jdk 1.7及以前
Consumer consumer = new Consumer() {
public void accept(String s) {
System.out.println(s);
}
};
// jdk 1.8 只有一个参数是小括号可以生路
Consumer consumer1 = s -> System.out.println(s);
2.5、两个参数,并且有返回值
// jdk 1.7及以前
Comparator comparator = new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2 ;
}
};
// jdk 1.8
Comparator comparator1 = (o1,o2) -> {return o1 - o2;};
2.6、Lambda体中只有一条语句时,return与大括号可以省略
// jdk 1.7及以前
Comparator comparator = new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2 ;
}
};
// jdk 1.8
Comparator comparator1 = (o1,o2) -> o1 - o2;
3、示例
引入lambda表达式之前,查询年龄大于20岁员工,查询薪资大于5000的员工
List persons = new ArrayList<>();
@Before
public void init(){
persons = Arrays.asList(
new Person("vesus1",18,3333),
new Person("vesus2",28,6666),
new Person("vesus3",35,7777),
new Person("vesus4",96,2222),
new Person("vesus5",10,2222),
new Person("vesus6",45,4444)
);
}
@Test//查询年龄大于20岁的员工,并输出
public void testFilterAge(){
List newlist = new ArrayList<>();
for (Person person : persons) {
if (person.getAge()>20){
newlist.add(person);
}
}
System.out.println("----------输出--------------");
System.out.println(newlist);
}
@Test//查询薪资大于5000岁的员工,并输出
public void testFilterSalary(){
List newlist = new ArrayList<>();
for (Person person : persons) {
if (person.getSalary()>5000){
newlist.add(person);
}
}
System.out.println("----------输出--------------");
System.out.println(newlist);
}
如果加入其它的过滤条件,需要增加新的方法,可扩展性较差,进行优化
策略模式进行优化
/**
* @Description: 定义断言接口
* @Author: vesus
* @CreateDate: 2019/1/7 下午2:44
* @Version: 1.0
*/
public interface MyPredicate {
public boolean test(T t);
}
/**
* @Description: 年龄断言实现类
* @Author: vesus
* @CreateDate: 2019/1/7 下午2:47
* @Version: 1.0
*/
public class AgePredicate implements MyPredicate {
public boolean test(Person person) {
return person.getAge()> 20;
}
}
/**
* @Description: 薪资断言实现类
* @Author: vesus
* @CreateDate: 2019/1/7 下午2:50
* @Version: 1.0
*/
public class SalaryPredicate implements MyPredicate {
@Override
public boolean test(Person person) {
return person.getSalary()>5000;
}
}
public boolean check(Person person ,MyPredicate myPredicate){
return myPredicate.test(person);
}
@Test//查询年龄大于20岁的员工,并输出
public void testFilterAge1(){
List newlist = new ArrayList<>();
for (Person person : persons) {
if (check(person,new AgePredicate())){
newlist.add(person);
}
}
System.out.println("----------输出--------------");
System.out.println(newlist);
}
@Test//查询薪资大于5000岁的员工,并输出
public void testFilterSalary1(){
List newlist = new ArrayList<>();
for (Person person : persons) {
if (check(person,new SalaryPredicate())){
newlist.add(person);
}
}
System.out.println("----------输出--------------");
System.out.println(newlist);
}
如果有其他条件可以进行很好的扩展,但是两个扩展的类只用到了一次,很多的时候是空闲的,继续对其进行优化。
匿名内部类
@Test//查询年龄大于20岁的员工,并输出
public void testFilterAge2(){
List newlist = new ArrayList<>();
for (Person person : persons) {
boolean ischeck = check(person, new MyPredicate() {
public boolean test(Person person) {
return person.getAge()>20;
}
});
if (ischeck){
newlist.add(person);
}
}
System.out.println("----------输出--------------");
System.out.println(newlist);
}
@Test//查询薪资大于5000岁的员工,并输出
public void testFilterSalary2(){
List newlist = new ArrayList<>();
for (Person person : persons) {
boolean ischeck = check(person, new MyPredicate() {
public boolean test(Person person) {
return person.getSalary()>5000;
}
});
if (ischeck){
newlist.add(person);
}
}
System.out.println("----------输出--------------");
System.out.println(newlist);
}
lambda表达式
@Test//查询年龄大于20岁的员工,并输出
public void testFilterAge3(){
List newlist = new ArrayList<>();
for (Person person : persons) {
boolean ischeck = check(person,(p)->{ return p.getAge()>20;});
if (ischeck){
newlist.add(person);
}
}
System.out.println("----------输出--------------");
System.out.println(newlist);
}
@Test//查询薪资大于5000岁的员工,并输出
public void testFilterSalary3(){
List newlist = new ArrayList<>();
for (Person person : persons) {
boolean ischeck = check(person, p -> p.getSalary()>5000);
if (ischeck){
newlist.add(person);
}
}
System.out.println("----------输出--------------");
System.out.println(newlist);
}
二、函数式接口
1、简介
2、jdk提供的函数是接口
Java SE 7中已经存在的函数式接口:
- java.lang.Runnable
- java.util.concurrent.Callable
- java.security.PrivilegedAction
- java.util.Comparator
- java.io.FileFilter
- java.beans.PropertyChangeListener
Java SE 8中增加了一个新的包:java.util.function,它里面包含了常用的函数式接口
Consumer——接收T对象,不返回值
Supplier——提供T对象(例如工厂),不接收值
Function——接收T对象,返回R对象
Predicate——接收T对象并返回boolean
UnaryOperator——接收T对象,返回T对象
BinaryOperator——接收两个T对象,返回T对象
除了上面的这些基本的函数式接口,还提供了一些针对原始类型(Primitive type)的特化(Specialization)函数式接口,例如IntSupplier和LongBinaryOperator。(我们只为int、long和double提供了特化函数式接口,如果需要使用其它原始类型则需要进行类型转换)同样的我们也提供了一些针对多个参数的函数式接口,例如BiFunction
2.1、Consumer :消费型接口,有参无返回值
/**
* Consumer 消费型接口
* @param str
* @param con
*/
public void changstr(String str, Consumer conn){
conn.accept(str);
}
@Test
public void testChangstr(){
changstr("hello",(str)-> System.out.println(str));
}
2.2、Supplier :供给型接口,无参有返回值
/**
* Supplier 供给型接口
* @param sup
* @return
*/
public String getValue(Supplier supplier){
return supplier.get();
}
@Test
public void testGetValue(){
String value =getValue(()->{return "hello";});
System.out.println(value);
}
2.3、Function
/**
* Function 函数式接口
* @param num
* @param fun
* @return
*/
public Long changeNum(Long t,Function func){
return func.apply(t);
}
@Test
public void testChangeNum(){
Long num = changeNum(100L,(t)->{return 200L+t;});
System.out.println(num);
}
2.4、Predicate: 断言型接口,有参有返回值,返回值是boolean类型
/**
* Predicate断言行接口
* @param str
* @param predicate
* @return
*/
public boolean judge(String str, Predicate predicate){
return predicate.test(str);
}
@Test
public void testJudge(){
boolean islength = judge("helloword",str-> str.length() >5);
System.out.println(islength);
}
4、自定义函数式接口
3.1、定义
@FunctionalInterface
public interface MyFunc {
public double getValue();
}
###带有泛型的函数式接口
@FunctionalInterface
public interface MyFuncGeneric {
public T getValue(T t);
}
3.2 调用
public class MyFuncTest {
@Test
public void testMyFunc(){
MyFunc myFunc = ()-> {return 100D ;};
System.out.println(myFunc.getValue());
}
@Test
public void testMyFuncGeneric(){
MyFuncGeneric myFuncGeneric = (t)-> {return "hello "+t;};
}
}
三、方法引用与构造器引用
若lambda体中的内容有方法已经实现了,那么可以使用“方法引用”
也可以理解为方法引用是lambda表达式的另外一种表现形式并且其语法比lambda表达式更加简单
1、方法引用
方法引用有很多种,它们的语法如下:
1.1、静态方法引用:
类::静态方法名 (ClassName::methodName)
BiFunction biFun = (x,y)->Integer.compare(x,y);
Integer result = biFun.apply(10,20);
System.out.println(result);
-----------------------------------------------------------------------
BiFunction biFun = Integer::compare ;
Integer result = biFun.apply(10,20);
System.out.println(result);
1.2、实例上的实例方法引用
对象::实例方法名(instanceReference::methodName)
ComparisonProvider myComparisonProvider = new ComparisonProvider();
Person[] pArr = new Person[]{new Person("vesus1",18,3333),
new Person("vesus2",36,8888)};
Arrays.sort(pArr, new Comparator() {
public int compare(Person o1, Person o2) {
return myComparisonProvider.compareByName(o1,o2);
}
});
Arrays.sort(pArr, (o1,o2)->{
return myComparisonProvider.compareByName(o1,o2);
});
-----------------------------------------------------------------------
Arrays.sort(pArr, myComparisonProvider::compareByName);
1.3、类型上的实例方法引用:ClassName::methodName
类::实例方法名(lambda参数列表中第一个参数是实例方法的调用 者,第二个参数是实例方法的参数时可用)
String[] stringArray = {"Barbara", "James", "Mary", "John", "Patricia"};
Arrays.sort(stringArray, new Comparator() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
Arrays.sort(stringArray,(o1,o2) -> o1.compareToIgnoreCase(o2));
-----------------------------------------------------------------------
Arrays.sort(stringArray,String::compareToIgnoreCase);
2、构造方法引用 Class::new
2.1、构造方法引用 类名::new
Supplier supplier = ()-> new Person();
Supplier supplier1 = Person::new;
System.out.println(supplier.get());
2.2、构造方法引用 类名::new (带参数)
@FunctionalInterface
public interface MyConstruct {
public T getValue(X x,Y y,Z z);
}
MyConstruct myConstruct = (x,y,z)-> new Person(x,y,z);
-----------------------------------------------------------------------
MyConstruct myConstruct1 = Person::new;
System.out.println(myConstruct1.getValue("vesus1",18,3333D));
2.3、数组构造方法引用 TypeName[]::new
IntFunction array = (x)-> new int[x] ;
IntFunction array1 = int[]::new ;