Java8 引入了 Lambda 表达式,使用 Lambda 表达式可让代码更加简洁。Lambda 表达式其实也就是一个匿名函数,咱们能够用它去代替匿名函数,咱们先来看一个例子java
咱们用接口 Runnable 举个例子express
public static void main(String[] args) { // 匿名函数 new Thread(new Runnable() { public void run() { System.out.println("anonymous function"); } }).start(); // lambda 表达式 new Thread(() -> System.out.println("lambda")).start(); }
从上的例子能够看出咱们使用 () -> {} 的代码块代替了整个匿名函数app
Lambda 表达式的语法格式以下
( parameters ) -> expression
( parameters ) -> {statements;}函数
- 能够不须要声明参数类型,编译器能够统一识别参数值。
- 一个参数时能够不定义圆括号,但多个参数须要定义圆括号。
- 若是主体只有一个表达式返回值则编译器会自动返回值,大括号须要指定明表达式返回了一个数值(若是接口方法返回类型为 void 则不用)。
Lambda 表达式的简单例子this
// 无参数,返回值为 10 () -> 10 // 单参数(数字类型),返回其2倍的值 x -> 2 * x // 多个参数(数字),并返回他们的差值 (x, y) -> x – y // 声明参数类型,返回他们的和 (int x, int y) -> return x + y // 声明参数类型,并在控制台打印,不返回任何值(接口方法返回类型为 void) (String s) -> System.out.print(s)
咱们能够将lambda表达式做为参数传递给方法,也就是说容许把函数做为一个方法的参数。code
建立一个 Calculator 的函数接口。 在 Calculator 中有一个称为 calculate 的方法,它接受两个 int 参数并返回一个 int 值。 在 engine 方法中,它接受函数接口 Calculator 做为参数。在主方法中,用不一样的lambda表达式调用 engine 方法四次对象
public class LambdaTest { public static void main(String[] argv) { engine((x, y) -> x + y); engine((x, y) -> x * y); engine((x, y) -> x / y); engine((x, y) -> x % y); } private static void engine(Calculator calculator) { int x = 2, y = 4; int result = calculator.calculate(x, y); System.out.println(result); } } @FunctionalInterface interface Calculator { int calculate(int x, int y); }
lambda 表达式不定义本身的范围。 若是咱们在 lambda 中使用关键字
this
和super
,this
表明着 lambda 表达式所被包含的类接口
变量做用域作用域
lambda 表达式与其外部方法具备相同的范围。 lambda表达式不会建立本身的做用域。get
lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,不然会编译错误。
public static void main(String args[]) { final int num = 1; Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); s.convert(2); // 输出结果为 3 } public interface Converter<T1, T2> { void convert(int i); }
lambda 表达式的局部变量能够不用声明为 final,可是必须不可被后面的代码修改(即隐性的具备 final 的语义)
int num = 1; Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); s.convert(2); num = 5; // Local variable num defined in an enclosing scope must be final or effectively final
在 Lambda 表达式当中不容许声明一个与局部变量同名的参数或者局部变量
String first = ""; Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length()); //编译会出错
函数式接口只是具备一个方法的接口,用做 lambda 表达式的类型。
一般会使用 @FunctionalInterface 注解来标注了函数式接口
在 java8 中为咱们定义了不少经常使用的函数式接口,它们都放在java.util.function包下面,通常有如下经常使用的四大核心接口
函数式接口 | 参数类型 | 返回类型 | 描述 |
---|---|---|---|
Consumer<T>(消费型接口) | T | void | 对类型为T的对象应用操做。void accept(T t) |
Supplier<T>(供给型接口) | 无 | T | 返回类型为T的对象。 T get(); |
Function<T, R>(函数型接口) | T | R | 对类型为T的对象应用操做并返回R类型的对象。R apply(T t); |
Predicate<T>(断言型接口) | T | boolean | 肯定类型为T的对象是否知足约束。boolean test(T t); |
方法引用经过方法的名字来指向一个方法。
方法引用可使语言的构造更紧凑简洁,减小冗余代码。
方法引用使用一对冒号 ::
使用构造函数引用的语法是 ClassName::new
Function<String,String> func1 = str -> new String(str); Function<String,String> func2 = String::new;
方法引用的通常语法是 Qualifier::MethodName
Function<Integer, String> func1 = x -> Integer.toBinaryString(x); Function<Integer, String> func2 = Integer::toBinaryString;
Supplier<Integer> supplier = () -> "www.w3cschool.cn".length(); Supplier<Integer> supplier1 = "www.w3cschool.cn"::length;
Function<String[],List<String>> asList = Arrays::<String>asList; System.out.println(asList.apply(new String[]{"a","b","c"}));