Skip to main content
 首页 » 编程设计

java lambda表达式(2)

2022年07月19日138Terrylee

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); 
 



本文参考链接:https://blog.csdn.net/neweastsun/article/details/52902387
阅读延展