JDK1.8新特性---lambda表达式

1.Lambda 表达式
首先看看在老版本的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对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。

在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
看到了吧,代码变得更段且更具有可读性,但是实际上还可以写得更短:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字,但是你还可以写得更短点:
Collections.sort(names, (a, b) -> b.compareTo(a));
接下来我们看看lambda表达式还能作出什么更方便的东西来:

2、函数式接口
Lambda 表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的 接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加 @FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
示例如下:

@FunctionalInterface
interface Converter {
T convert(F from);
}
验证: Converter converter = new Converter {

        @Override
        public Integer converter(String form) {
            return Integer.valueOf(form);
        }
        
    };

    // 简化
    converter = (String form) -> {return Integer.valueOf(form);};
    // 简化
    converter = (form) -> Integer.valueOf(form);
    Integer integer = converter.converter("123");
    System.out.println(integer);

需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。

3.方法与构造函数引用
前一节中的代码还可以通过静态方法引用来表示:
Converter converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted); // 123

Java 8 允许你使用 :: 关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法:

    String something = "JavaEE";
    Converter converter1 = something::startsWith;
    boolean res = converter1.converter("Java");
    System.out.println(res);

接下来看看构造函数是如何使用::关键字来引用的,首先我们定义一个包含多个构造函数的简单类:
class Person {
String firstName;
String lastName;
Person() {}
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
接下来我们指定一个用来创建Person对象的对象工厂接口:

interface PersonFactory

{
P create(String firstName, String lastName);
}
这里我们使用构造函数引用来将他们关联起来,而不是实现一个完整的工厂:

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

我们只需要使用 Person::new 来获取Person类构造函数的引用,Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。

四、Lambda 作用域
在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。

五、访问局部变量
我们可以直接在lambda表达式中访问外层的局部变量:
复制代码 代码如下:

final int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3

但是和匿名对象不同的是,这里的变量num可以不用声明为final,该代码同样正确:
复制代码 代码如下:

int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3

不过这里的num必须不可被后面的代码修改(即隐性的具有final的语义),例如下面的就无法编译:
复制代码 代码如下:

int num = 1;
Converter stringConverter =
(from) -> String.valueOf(from + num);
num = 3;

在lambda表达式中试图修改num同样是不允许的。
六、访问对象字段与静态变量
和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。该行为和匿名对象是一致的:
复制代码 代码如下:
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);
};
}
}

你可能感兴趣的:(JDK1.8新特性---lambda表达式)