`

2.Lambda 表达式

阅读更多
在说一下Lambda表达式之前,我们先了解下为什么java要引入Lambda表达式

在java8 之前要将行为参数化我们有两种选择:
1.策略模式,根据参数传入的具体实现决定方法的实现
2.匿名内部类。
1的缺点是要新增新的行为必须创建新的行为并实现接口;2的缺点是不得不写很多模板代码,可读性差。

引入Lambda 前提条件

在很多函数式编程语言中允许将函数作为值,Java8也新增了这一特性,即允许方法作为值来传递,实现行为参数化。
在Java8之前筛选出隐藏文件可能需要这么做:

 File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
    public boolean accept(File file) {
    return file.isHidden();
}
 


Java8之后只需要这么做:

File[] hiddenFiles = new File(".").listFiles(File::isHidden);

其中File::isHidden被称为方法应用,只要在方法体中存在执行体,方法应用就可以传递代码。

Lambda——匿名函数

函数式编程的概念:编写把函数作为值来传递的程序。

add方法对两个int值进行求和写作: (int x,int y) -> x+y,这部分可替代写个工具类然后调用如: Math::add,这样写更为简介,也不需要编辑新的类。

Lambda特性:
1.匿名:lambda表达式是没有名字的
2.函数:为什么叫函数而不是方法呢,因为Lambda函数不像方法那样属于某个类。但和方法一样Lambda有参数列表、函数主体返回类型、抛出异常。
3.传递:可作为值在方法参数中传递】
4.简洁
Lambda语法:
    (parameters) -> expression或 (parameters) -> { statements; }
从左往右 lambda表达式有 参数列表、箭头、和函数主体构成。
函数体中使用了花括号需要显式使用return 返回,不使用花括号则不需要return关键字

函数式接口:
既然函数可作为值来传递那么肯定需要相应的规则,类似与我们把方法参数限定为指定接口类型一样,需要传递实现接口的类或者匿名内部类作为值,同样这里也按照规范定义了函数式接口,用来限定传递代码的参数和返回值(注意:Java8并没有引入函数这一类型)。

函数式接口与之前的接口区别就是只允许定义一个抽象方法(见下面),原因就不用多说了,都可以理解,函数式接口中方法的签名被叫做Lambda表达式的签名,编译器会根据函数式接口的签名和上下文进行类型推断保证不会出现编译错误,下面的是有效的。
  Runnable a = () -> System.out.println(111);
        a.run();

在Java8中类似Runnable、Comparable都是函数式接口。

@FunctionalInterface 注解

1、该注解只能标记在"有且仅有一个抽象方法"的接口上。

2、JDK8接口中的静态方法和默认方法,都不算是抽象方法。

3、接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。

4、该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响,类似@override。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。

使用函数式接口,java.util.function包

为了简化Java内置了常见的几种函数式接口Predicate<T>、Consumer<T>和Function<T,R>
Predicate有一个抽象方法test,输入为人意类型返回 boolean类型
Consumer有一个抽象方法accept,返回为空,输入为任意类型。
Function 有一个抽象方法返回为R类型输入为T类型。

方法引用

在大多数情况下我们应该考虑复用已有的东西而不是重新造轮子,方法引用就是Lambda表达式的一个快捷方式,即方法应用会根据已有的方法实现来创建一个Lambda表达式。当你需要使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面。例如, Apple::getWeight就是引用了Apple类中定义的方法getWeight。

方法引用主要有三类。
(1) 指向静态方法的方法引用(例如Integer的parseInt方法,写作Integer::parseInt)。
(2) 指向任意类型实例方法的方法引用(例如String的length方法,写作 String::length)。
(3) 指向现有对象的实例方法的方法引用(假设你有一个局部变量expensiveTransaction 用于存放Transaction类型的对象,它支持实例方法getValue,那么你就可以写expensive- Transaction::getValue)。
例如:
List<String> str = Arrays.asList("a","b","A","B");
str.sort((s1, s2) -> s1.compareToIgnoreCase(s2));

    List<String> str = Arrays.asList("a","b","A","B");
    str.sort(String::compareToIgnoreCase);

下面的写法是等效的:
Function<String, Integer> stringToInteger = (String s) -> Integer.parseInt(s);
Function<String, Integer> stringToInteger = Integer::parseInt;

还有一种特殊的函数应用:构造函数应用



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics