使用场景

lambda表达式 是java8中新增的语法,体现了函数式编程的思想,即把函数当作一个对象。相当于把一个功能(function)当作一个对象。

就像数学中 求一个数的平方加上它的两倍再加1(功能)可以写成表达式 f(x) = =x*x + 2x +1 一样, 然后用f(x)就可以简单表示 x*x + 2x + 1

然后使用场景:
最简单且容易理解的场景就是 需要实现一个接口,这个接口只有一个抽象方法, 然后把匿名类的写法改成 lambda表达式

例如在用线程的时候,我们经常需要实现 Runnable 接口, 这个接口只有一个抽象方法 run,这个时候就可以使用 lambda 表达式(具体使用如下)。 为什么是只有一个抽象方法呢?因为一个函数只对应一个功能, 就像f(x)不能同时表示 2x+13x+1

示例: 实现一个runnable 接口 传给Thread

// 最麻烦的写法, 
public class Task implement Runnable {
	public void run() {
		System.out.println("run");
	}
}
Thread t = new Thread(new Task());

// 匿名类   (一般这个时候 IDEA 都会给出优化提示)
Thread t1 = new Thread(new Runnable() {
	public void run() {
		System.out.println("run");
	}
};

// lambda
Thread t2 = new Thread(() -> System.out.println("run"));

所以, lambda 最大的好处就是简化代码

使用方式如下

基础版 ->

语法

(参数) -> {执行语句}

  • 如果仅有一个参数, 对应的括号可以省略;
  • 只有一条执行语句时, 大括号和return也可以省略;
  • 参数类型可以省略

简化实现单一方法的接口的代码, 即函数式接口.

使用示例

例如使用匿名类实现一个Runnable 接口, 传统方式如下

Runnable r = new Runable() {
	public void run() {
		System.out.println("do something");
	}
};

而使用lambda表达式,

Runnable r = () -> System.out.println("do something");

对于带参数的接口, 如 Comparator 接口(比较两个对象的大小)

Comparator<Integer> c = new Comparator<Integer>(){
	public int compare(Integer o1, Integer o2) {
		return o1 - o2;
	}
};

// lambda
Comparator<Integer> c = (Integer o1, Integer o2) -> o1 - o2;
Comparator<Integer> c = (o1, o2) -> o1 - o2;

因为有Comparator类型声明, 所以jvm知道此处lambda实现的是哪个接口, 所以参数类型可以省略, 如果直接作为方法参数, 同样由参数列表确定实现的接口.

这样的话, 代码是不是简洁了很多. 有时候代码还能更简洁

进阶版 ::

语法

类名::静态方法类名::new对象::非静态方法

利用已有的方法实现相同结构的函数式接口, (参数列表和返回类型相同).

注意: 引用的方法参数列表和返回类型必须和接口方法一致

使用示例

  • 引用静态方法
    还是实现一个Comparator的接口, 比较Integer的大小
// 使用Integer的compare方法实现comparator接口, 是不是更简单了
Comparator<Integer> c = Integer::compare;

// 这是Integer.compare的方法源码
public static int compare(int x, int y) {
	return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

其实上面的方法可以理解为, 直接在实现方法中直接调用Integer.compare的方法

Comparator<Integer> c = new Comparator<Integer>(){
	public int compare(Integer o1, Integer o2) {
		return Integer.compare(o1, o2);
	}
};
  • 实例方法

就随便写一个方法了
实现Supplier接口, 在里面调用object.toString方法

Object o = new Object();
Supplier<String> c = o::toString;

//相当于
Supplier<String> c1 = new Supplier<String>(){
    public String get() {
        return o.toString();
    }
};

// Supplier 接口(java四个基本函数式接口之一)
public interface Supplier<T> {
	T get();
}
  • 构造方法
// lambda
Supplier<String> s = String::new;

// 普通形式
Supplier<String> c1 = new Supplier<String>(){
    public String get() {
        return new String();
    }
};

有人可能会疑惑, String有那么多构造方法, 它怎么知道我是引用的无参的那个, 这是因为要实现的接口的方法就是无参的。 所以存在重载方法时,会根据实现的接口的参数和返回类型选择对应的方法.