JDK8新特性(一)

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支持。

  • 小组:对特定技术内容,比如安全、网络、HotSpot等有共同兴趣的组织和个人
  • 项目:编写代码、文档以及其他工作,至少由一个小组赞助和支持,比如最近的Lambda计划,JigSaw计划等

一、Lambda表达式

  1. 背景

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)的方法。匿名内部类并不是一个好的选择,因为:

  • 语法过于冗余
  • 匿名类中的this和变量名容易使人产生误解
  • 类型载入和实例创建语义不够灵活
  • 无法捕获非final的局部变量
  • 无法对控制流进行抽象

上面的多数问题均在Java SE 8中得以解决:

  • 通过提供更简洁的语法和局部作用域规则,Java SE 8彻底解决了问题1和问题2
  • 通过提供更加灵活而且便于优化的表达式语义,Java SE 8绕开了问题3
  • 通过允许编译器推断变量的“常量性”(finality),Java SE 8减轻了问题4带来的困扰

不过,Java SE 8的目标并非解决所有上述问题。因此捕获可变变量(问题4)和非局部控制流(问题5)并不在Java SE 8的范畴之内。(尽管我们可能会在未来提供对这些特性的支持)

  1. lambda表达式(lambda expressions)

匿名类型最大的问题就在于其冗余的语法。有人戏称匿名类型导致了“高度问题”(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<String> consumer = new Consumer<String>() {
    public void accept(String s) {
        System.out.println(s);
    }
};
// jdk 1.8
Consumer<String> consumer1 = (s)-> System.out.println(s);

2.4、只有一个参数的构造函数,小括号可以省略

//jdk 1.7及以前
Consumer<String> consumer = new Consumer<String>() {
    public void accept(String s) {
        System.out.println(s);
    }
};
// jdk 1.8 只有一个参数是小括号可以生路
Consumer<String> consumer1 = s ->  System.out.println(s);

2.5、两个参数,并且有返回值

// jdk 1.7及以前
Comparator<Integer> comparator = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1 - o2 ;
    }
};
// jdk 1.8
Comparator<Integer> comparator1 = (o1,o2) -> {return o1 - o2;};

2.6、Lambda体中只有一条语句时,return与大括号可以省略

// jdk 1.7及以前
Comparator<Integer> comparator = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1 - o2 ;
    }
};
// jdk 1.8
Comparator<Integer> comparator1 = (o1,o2) -> o1 - o2;

3、示例

引入lambda表达式之前,查询年龄大于20岁员工,查询薪资大于5000的员工

List<Person> 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<Person> 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<Person> 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<T> {

    public boolean test(T t);
}

/**
 * @Description: 年龄断言实现类
 * @Author: vesus
 * @CreateDate: 2019/1/7 下午2:47
 * @Version: 1.0
 */
public class AgePredicate implements MyPredicate<Person> {
    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<Person> {
    @Override
    public boolean test(Person person) {
        return person.getSalary()>5000;
    }
}

public boolean check(Person person ,MyPredicate<Person> myPredicate){
    return myPredicate.test(person);
}

@Test//查询年龄大于20岁的员工,并输出
public void testFilterAge1(){
    List<Person> 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<Person> 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<Person> newlist = new ArrayList<>();
    for (Person person : persons) {

        boolean ischeck = check(person, new MyPredicate<Person>() {
            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<Person> newlist = new ArrayList<>();
    for (Person person : persons) {

        boolean ischeck = check(person, new MyPredicate<Person>() {
            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<Person> 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<Person> 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、简介

  • 只包含一个抽象方法的接口,称为函数式接口。
  • 你可以通过Lambda 表达式来创建该接口的对象。(若Lambda 表达式抛出一个异常,那么该异常需要在目标接口的抽象方法上进行声明)。
  • 我们可以在任意函数式接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。

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>——接收T对象,不返回值
Supplier<T>——提供T对象(例如工厂),不接收值
Function<T, R>——接收T对象,返回R对象
Predicate<T>——接收T对象并返回boolean
UnaryOperator<T>——接收T对象,返回T对象
BinaryOperator<T>——接收两个T对象,返回T对象

除了上面的这些基本的函数式接口,还提供了一些针对原始类型(Primitive type)的特化(Specialization)函数式接口,例如IntSupplier和LongBinaryOperator。(我们只为int、long和double提供了特化函数式接口,如果需要使用其它原始类型则需要进行类型转换)同样的我们也提供了一些针对多个参数的函数式接口,例如BiFunction<T, U, R>,它接收T对象和U对象,返回R对象。

2.1、Consumer :消费型接口,有参无返回值

/**
 * Consumer<T> 消费型接口
 * @param str
 * @param con
 */ 
public void changstr(String str, Consumer<String> conn){
    conn.accept(str);
}

@Test
public void testChangstr(){
    changstr("hello",(str)-> System.out.println(str));
}

2.2、Supplier :供给型接口,无参有返回值

/**
 * Supplier<T> 供给型接口
 * @param sup
 * @return
 */
public String getValue(Supplier<String> supplier){
    return supplier.get();
}

@Test
public void testGetValue(){
    String value =getValue(()->{return "hello";});
    System.out.println(value);
}

2.3、Function <T,R>:函数式接口,有参有返回值

/**
 *  Function<T,R> 函数式接口
 * @param num
 * @param fun
 * @return
 */
public Long changeNum(Long t,Function<Long,Long> 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<T>断言行接口
 * @param str
 * @param predicate
 * @return
 */
public boolean judge(String str, Predicate<String> 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<T> {
    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<String> myFuncGeneric = (t)-> {return "hello "+t;};
    }
}

三、方法引用与构造器引用

若lambda体中的内容有方法已经实现了,那么可以使用“方法引用”

也可以理解为方法引用是lambda表达式的另外一种表现形式并且其语法比lambda表达式更加简单

1、方法引用

方法引用有很多种,它们的语法如下:

  • 静态方法引用:ClassName::methodName
  • 实例上的实例方法引用:instanceReference::methodName
  • 超类上的实例方法引用:super::methodName
  • 类型上的实例方法引用:ClassName::methodName
  • 数组构造方法引用:TypeName[]::new

1.1、静态方法引用:

类::静态方法名 (ClassName::methodName)

BiFunction<Integer,Integer,Integer> biFun = (x,y)->Integer.compare(x,y);
Integer result = biFun.apply(10,20);
System.out.println(result);
-----------------------------------------------------------------------
BiFunction<Integer,Integer,Integer> 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<Person>() {
    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<String>() {
    @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<Person> supplier = ()-> new Person();

Supplier<Person> supplier1 = Person::new;

System.out.println(supplier.get());

2.2、构造方法引用 类名::new (带参数)

@FunctionalInterface
public interface MyConstruct<X,Y,Z,T> {

    public T getValue(X x,Y y,Z z);
}

MyConstruct<String,Integer,Double,Person> myConstruct = (x,y,z)-> new Person(x,y,z);
-----------------------------------------------------------------------
MyConstruct<String,Integer,Double,Person> myConstruct1 = Person::new;
System.out.println(myConstruct1.getValue("vesus1",18,3333D));

2.3、数组构造方法引用 TypeName[]::new

IntFunction<int[]> array = (x)-> new int[x] ;

IntFunction<int[]> array1 = int[]::new ;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值