Java Lambda 表达式使用

Java8 引入了 Lambda 表达式,使用 Lambda 表达式可让代码更加简洁。Lambda 表达式其实也就是一个匿名函数,咱们能够用它去代替匿名函数,咱们先来看一个例子java

一、Lambda 表达式语法

咱们用接口 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 行为参数化和变量做用域

咱们能够将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 中使用关键字 thissuperthis 表明着 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);

四、方法引用

方法引用经过方法的名字来指向一个方法。
方法引用可使语言的构造更紧凑简洁,减小冗余代码。
方法引用使用一对冒号 ::

1)构造函数引用

使用构造函数引用的语法是 ClassName::new

Function<String,String> func1  = str ->  new String(str);

Function<String,String> func2  = String::new;

2) 静态方法引用

方法引用的通常语法是 Qualifier::MethodName

Function<Integer, String> func1  = x -> Integer.toBinaryString(x);

Function<Integer, String> func2  = Integer::toBinaryString;

3) 实例方法引用

Supplier<Integer> supplier  = () ->  "www.w3cschool.cn".length(); 

Supplier<Integer> supplier1  = "www.w3cschool.cn"::length;

4) 通用方法引用

Function<String[],List<String>> asList = Arrays::<String>asList;
    
System.out.println(asList.apply(new String[]{"a","b","c"}));
相关文章
相关标签/搜索