JAVA~适合新手和复习~基础四(Lambda表达式)

发布时间 2023-03-24 10:19:42作者: 这里那里

 Lambda 表达式

Lambda 表达式,也可称为闭包,Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。本质上是面向过程的开发

Lambda 表达式实例

Lambda 表达式的简单例子:

// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

 示例:

 1 public class Java8Tester {
 2    public static void main(String args[]){
 3       Java8Tester tester = new Java8Tester();
 4         
 5       // 类型声明
 6       MathOperation addition = (int a, int b) -> a + b;
 7         
 8       // 不用类型声明
 9       MathOperation subtraction = (a, b) -> a - b;
10         
11       // 大括号中的返回语句
12       MathOperation multiplication = (int a, int b) -> { return a * b; };
13         
14       // 没有大括号及返回语句
15       MathOperation division = (int a, int b) -> a / b;
16         
17       System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
18       System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
19       System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
20       System.out.println("10 / 5 = " + tester.operate(10, 5, division));
21         
22       // 不用括号
23       GreetingService greetService1 = message ->
24       System.out.println("Hello " + message);
25         
26       // 用括号
27       GreetingService greetService2 = (message) ->
28       System.out.println("Hello " + message);
29         
30       greetService1.sayMessage("Runoob");
31       greetService2.sayMessage("Google");
32    }
33     
34    interface MathOperation {
35       int operation(int a, int b);
36    }
37     
38    interface GreetingService {
39       void sayMessage(String message);
40    }
41     
42    private int operate(int a, int b, MathOperation mathOperation){
43       return mathOperation.operation(a, b);
44    }
45 }
46 执行以上脚本,输出结果为:
47 
48 $ javac Java8Tester.java 
49 $ java Java8Tester
50 10 + 5 = 15
51 10 - 5 = 5
52 10 x 5 = 50
53 10 / 5 = 2
54 Hello Runoob
55 Hello Google

 

函数式接口

要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法 。

定义方式:

法1:

@FunctionalInterface
interface NoParameterNoReturn {
    //注意:只能有一个方法
    void test();
}

法2:

@FunctionalInterface
interface NoParameterNoReturn {
    void test();
    default void test2() {
        System.out.println("JDK1.8新特性,default默认方法可以有具体的实现");
    }
}

变量作用域

lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

public class Java8Tester {
 
   final static String salutation = "Hello! ";
   
   public static void main(String args[]){
      GreetingService greetService1 = message -> 
      System.out.println(salutation + message);
      greetService1.sayMessage("Runoob");
   }
    
   interface GreetingService {
      void sayMessage(String message);
   }
}
执行以上脚本,输出结果为:

$ javac Java8Tester.java 
$ java Java8Tester
Hello! Runoob
//ambda 表达式的局部变量可以不用声明为 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 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。

1 String first = "";  
2 Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length());  
3 //报错 :编译出错 

 

常用函数式接口

Supplier接口

Supplier接口是对象实例的提供者(生产者),定义了一个名叫get的抽象方法,它没有任何入参,并返回一个泛型T对象,具体源码如下:

package java.util.function;

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

源码比较简单,我们来个例子。这是表示口罩的类:

package one.more.study;

/**
 * 口罩
 */
public class Mask {
    public Mask(String brand, String type) {
        this.brand = brand;
        this.type = type;
    }
    /**
     * 品牌
     */
    private String brand;
    /**
     * 类型
     */
    private String type;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

下面我们使用Lambda表达式声明一个Supplier的实例:

Supplier<Mask> supplier = () -> new Mask("3M", "N95");
//用它来创建品牌为3M、类型为N95的Mask实例:

Mask mask = supplier.get();
System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
运行结果如下:


Brand: 3M, Type: N95

  

 
特别需要注意的是,本例中每一次调用get方法都会创建新的对象

Consumer接口

Consumer接口是一个类似消费者(只管取数据)的接口,定义了一个名叫accept的抽象方法,它的入参是一个泛型T对象,没有任何返回(void),主要源码如下:

package java.util.function;

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

 例子:

1 Supplier<Mask> supplier = () -> new Mask("3M", "N95");
2 Consumer<Mask> consumer = (Mask mask) -> {
3     System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
4 };
5 consumer.accept(supplier.get());

首先使用Lambda表达式声明一个Supplier的实例,它是用来创建品牌为3M、类型为N95的Mask实例;再使用Lambda表达式声明一个Consumer的实例,它是用于打印出Mask实例的相关信息;最后Consumer消费了Supplier生产的Mask。运行结果如下:

Brand: 3M, Type: N95

Predicate接口

Predicate接口是判断是与否的接口,定义了一个名叫test的抽象方法,它的入参是一个泛型T对象,并返回一个boolean类型,主要源码如下:

1 package java.util.function;
2 
3 @FunctionalInterface
4 public interface Predicate<T> {
5     boolean test(T t);
6 }

例子

Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Predicate<Mask> n95 = (Mask mask) -> "N95".equals(mask.getType());
Predicate<Mask> kn95 = (Mask mask) -> "KN95".equals(mask.getType());
System.out.println("是否为N95口罩:" + n95.test(supplier.get()));
System.out.println("是否为KN95口罩:" + kn95.test(supplier.get()));

首先使用Lambda表达式声明一个Supplier的实例,它是用来创建品牌为3M、类型为N95的Mask实例;再使用Lambda表达式声明一个Predicate的实例n95,它是用于判断是否为N95口罩;再使用Lambda表达式声明一个Predicate的实例kn95,它是用于判断是否为KN95口罩;最后分别用两个Predicate判断Supplier生产的Mask

运行结果如下:

是否为N95口罩:true
是否为KN95口罩:false

Function接口

Function接口是对实例进行处理转换的接口,定义了一个名叫apply的抽象方法,它的入参是一个泛型T对象,并返回一个泛型R对象,主要源码如下:  

package java.util.function;

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
例子
1 Supplier<Mask> supplier = () -> new Mask("3M", "N95");
2 Function<Mask, String> brand = (Mask mask) -> mask.getBrand();
3 Function<Mask, String> type = (Mask mask) -> mask.getType();
4 System.out.println("口罩品牌:" + brand.apply(supplier.get()));
5 System.out.println("口罩类型:" + type.apply(supplier.get()));

首先使用Lambda表达式声明一个Supplier的实例,它是用来创建品牌为3M、类型为N95的Mask实例;再使用Lambda表达式声明一个Function的实例brand,它是用于获取口罩的品牌;再使用Lambda表达式声明一个Function的实例type,它是用于获取口罩的类型;最后分别用两个Function分析Supplier生产的Mask

运行结果如下:

口罩品牌:3M
口罩类型:N95

 

BiFunction接口

Function接口的入参只有一个泛型对象,JDK还为我们提供了两个泛型对象入参的接口:BiFunction接口,主要源码如下:

package java.util.function;

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

例子

iFunction<String,String,Mask> biFunction = (String brand, String type) -> new Mask(brand, type);
Mask mask = biFunction.apply("3M", "N95");
System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
运行结果如下:

Brand: 3M, Type: N95

  

Supplier相关的接口

Consumer相关的接口

 

Predicate相关的接口

Function相关的接口