(三)lamda

lambda

lambda可以理解为匿名函数,由参数列表 箭头 函数主体组成
语法

(parameters)->expression 或 (parameters)->{statements;}

第一种只有一句表达式,会默认返回表达式的值,所以隐藏了return。例如

(Integer x)-> x+x

第二种用于有多个表达式逻辑的代码块,必须使用return明确返回值。

(Integer x)-> {
            System.out.println("start ++x");
            ++x;
            return x;
        };

函数接口

函数接口是仅有一个抽象方法的接口,例如Function接口

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

函数接口的作用是可以让lambda表达式为函数式接口的抽象方法提供实现,用lambda直接取代内部类
比如runnable内部类接口

Runnable r2 = new Runnable(){
    public void run(){
        System.out.println("Hello World 1");
    }
};

Runnable 的lambda方式

Runnable r1 = () -> System.out.println("Hello World 1");

这两种方式完全等价,可以说离开函数接口,lambda表达式没有任何作用,一个lambda函数始终是函数接口的实现。

类型推断

lambda表达式可以在编辑期间自动推断参数类型
例如

 Function<Integer,Integer> fs = (x)-> x+x;

该例子可以通过Function接口的泛型化参数推断出x是Integer类型的参数。

初学者如何写好lambda表达式

熟悉相关函数接口,明确函数接口抽象方法的结构(参数列表和返回值类型)
例如Function接口

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

观察抽象方法 R apply(T t);可见该抽象方法定义为由一个T类型的值返回一个R类型的返回值
例如

Function<Integer,String> fs = (x)-> {
          String helloString = "hello" + x.intValue();
          return helloString;
       };

声明为输入参数T为Integer类型,返回值R为String类型,所以lambda的参数列表数目(lambda参数可以自动推断)和函数接口抽象方法数目一致,lambda方法体返回结果类型和函数接口返回值类型一致即可。

方法引用

ClassName::staticMethod或者ClassName::instanceMethod
静态方法的引用

public class Main {

    public static void main(String[] args) {
        List<String> strings = new ArrayList<>();
        strings.forEach(Main::print);
    }
    public static void print(String abc){
        System.out.println(abc);
    }
}

需要注意的是所引用的方法需要和相关的函数接口匹配(和函数接口的参数类型和返回值一致),比如这个例子的forEach方法接受的函数接口是Consumer

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

Consumer是一个消费型的函数接口,接受一个T类型,无返回值

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

而我们的print方法接受一个String类型的参数,无返回值,且strings被限定为String类型,所以Consumer的T类型是String类型,因此print方法能和Consumer函数接口匹配。
实例方法引用

        List<String> list = new ArrayList<>();
        list.stream().sorted(String::compareTo);

静态方法引用与实例方法引用的区别

静态方法
ClassName::staticMethod ==== (x)->{statements}
实例方法引用
ClassName::staticMethod ==== (x,y)->{statements}
instanceObject::instanceMethod ===== (x)->{statements}
关注公众号,一起阅读IT经典书籍

关注公众号,一起阅读经典书籍