java8 lambda表达式(2)

java8 lambda表达式(2)

继续lambda表达式,结合简短的代码,详细深入说明lambda表达式。有兴趣也可以先读前一篇的内容。

1.    接口缺省方法

java8支持在接口中增加非抽象方法,也称为扩展方法。使用default关键字。示例如下:

interface Formula{

   double calculate(int a);

   defaultdouble sqrt(int a) {

       return Math.sqrt(a);

   }

}


Formula接口中定义了抽象方法calculate方法和default扩展方法。接口具体实现类只需要实现抽象方法,缺省方法sqrt可以直接使用。

Formulaformula=newFormula(){

    @Override

    publicdoublecalculate(inta){

        returnsqrt(a*100);

    }

};

formula.calculate(100);     // 100.0

formula.sqrt(16);           // 4.0


formula赋值为一个匿名对象。代码冗长,6行代码,就为了调用calculate方法,后面利用java8的漂亮的方式简洁实现。

2.    Lambda 表达式

首先,我们看看采用java8之前版本实现简单示例:

List<String>names=Arrays.asList("peter","anna","mike","xenia");

Collections.sort(names,newComparator<String>(){

    @Override

    publicintcompare(Stringa,Stringb){

        returnb.compareTo(a);

    }

});


static工具方法Collections.sort接收list和比较器,给list集合中所有元素进行排序。上面代码再次使用匿名比较器对象,传递给sort方法。

无需总是使用匿名对象,java8使用更简洁的语法实现,即lambda表达式。

Collections.sort(names, (Stringa, String b) -> {

   return b.compareTo(a);

});


还可以更简洁,表达式只有一句,可以省略return关键字以及花括号。

Collections.sort(names, (Stringa, String b) -> b.compareTo(a));

再简洁点,数据类型也可以省略,java编译器可以推到其数据类型。

Collections.sort(names, (a,b) -> b.compareTo(a));

下面让我们更深入了解lambda表达式,实际情况下如何应用。

3.    函数式接口

lambda表达式如何符合java相关规范?每个lambda表达式与指定的接口、给定类型保持一致。所以也成为函数式接口,必须包含恰好只有一个抽象方法的申明,每个lambda表达式类型需和抽象方法匹配。因为缺省方法不是抽象的,所有你可以自由地增加缺省方法至函数式接口中。

我们可以使用任意接口做为lambda表达式,只要该接口只包含一个抽象方法。为了保证接口符合该需求,你可以增加@FunctionalInterface注解进行限制。编译器根据该注解进行检查,当你试图增第二个抽象方法时,则会编译出错。示例如下:

@FunctionalInterface

interface Converter<F,T>{

    Tconvert(Ffrom);

}

Converter<String,Integer> converter=(from)->Integer.valueOf(from);

Integer converted=converter.convert("123");

System.out.println(converted);    // 123


需要说明下,上面的代码,不写注解也是可以的。

4.    引用方法和构造函数

lambda表达式,还可以引用方法和构造函数。上面的示例,也可以简单通过引用static方法实现。示例如下:

<pre name="code" class="java">Converter<String,Integer> converter=Integer::valueOf;

Integer converted=converter.convert("123");

System.out.println(converted);   // 123

 

java8支持通过::关键字引用方法或构造函数,上面示例展示如何引用static方法,那如何引用对象方法呢?看下面示例,Converter函数式接口前面已经定义,这里引用对象something的方法startsWith。方便吧,感慨下!

class Something{

    StringstartsWith(Strings){

        returnString.valueOf(s.charAt(0));

    }

}

Something something=newSomething();

Converter<String,String> converter=something::startsWith;

String converted=converter.convert("Java");

System.out.println(converted);    // "J"


让我们再看看::关键字如何引用构造函数,首先定义示例bean,带有两个构造函数。

class Person{

    StringfirstName;

    StringlastName;

    Person(){}

    Person(StringfirstName,StringlastName){

        this.firstName=firstName;

        this.lastName=lastName;

    }

}


下面定义person工厂接口,用于创建person对象。

interface PersonFactory<PextendsPerson>{

    Pcreate(StringfirstName,StringlastName);

}


代替手工实现工厂接口,我们使用::关键字引用构造器。当调用PersonFactory.create时,java编译器自动选择适合的构造函数。

PersonFactory<Person> personFactory=Person::new;

Person person=personFactory.create("Peter","Parker");


再提醒下,一定要有一个函数式接口哦,是不是觉得这个东东有点麻烦,还要自己定义,后面详述java8给我们准备啥了,这里暂且不表。

5.    Lambda 表达式作用域

lambda表达式访问外部变量有非常类似匿名对象。可以方法局部的fianl变量,也可以方法属性和static变量。

5.1.        访问局部变量

我们可以在lambda表达式里访问外部的局部变量。示例如下:

final int num=1;

Converter<Integer,String> stringConverter = (from)->String.valueOf(from+num);

stringConverter.convert(2);     // 3


与匿名对象的访问方式不同,这里可以不使用final关键字申明num局部变量,所以代码也可以这样。


但是,num变量其实编译时隐含为final类型,所以下面代码,不能编译通过。

int num=1;

Converter<Integer,String> stringConverter = (from)->String.valueOf(from+num);
 
stringConverter.convert(2);     // 3
<strong><span style="color:#A9B7C6;background:#2B2B2B"></span></strong>

在lambda表达式里面修改也是禁止的,记住,其实就是final类型。

5.2.        访问属性及静态变量

与局部变量相比,我们完全可以在lambda表达式里面访问或修改实例的属性和静态变量,这与我们熟悉的匿名对象访问方式一致。

classLambda4{

    static int outerStaticNum;

    int outerNum;

    voidtestScopes(){

        Converter<Integer,String> stringConverter1=(from)->{

            outerNum=23;

            returnString.valueOf(from);

        };

        Converter<Integer,String> stringConverter2=(from)->{

            outerStaticNum=72;

            returnString.valueOf(from);

        };

    }

}


5.3.        访问缺省接口方法

还记得前面的Formula接口示例吗?

接口 Formula 定义了缺省的sqrt 方法,其可以被每个Formula实例对象访问,包括匿名对象,但是不能使用lambda表达式访问。缺省方法不能被lambda表达式访问,所以下面的代码不能编译。

Formulaformula=(a)->sqrt(a*100);



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值