《Java 8 实战》Ch3: Lambda表达式(下):类型与

2019-04-24  本文已影响0人  WenxuanLi

李文轩 2019-04-23


3.5 类型的检查和判断;变量捕获限制

类型检查

    //Main
    List<Apple> heavierThan150g = filter(inventory, (Apple a) -> a.getWeight() > 150);
    
    //Lambda表达式的类型检查的过程
    //1. 找到filter方法的声明 -> filter(List<Apple> inventory, Predicate<Apple> p)
    //2. Lambda所在的第二个参数为 Predicate<Apple>,T绑定了Apple
    //3. Predicate<Apple> 是一个函数式接口,包含了一个test的抽象方法
    //4. test的函数描述符为 接受一个Apple对象,返回一个boolean值
    //5. 查看Lambda的签名和(4)的描述符是否一致,

类型推断

    //Lambda表达式的参数没有写出显式类型
    List<Apple> greenApples = filter(inventory, a -> "green".equals(a.getColor());
    
    //写出了显式类型,编译器没有进行类型推断
    Comparator<Apple> c = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
    
    //没有写出显式类型,编译器将进行类型推断
    Comparator<Apple> c = (a1, a2) -> a1.getWeight().compareTo(a2.getWeight());

Lambda使用局部变量

    //以下代码是有效的
    int portNumber = 1337;
    Runnable r = () -> System.out.println(portNumber);
    //以下代码是无效的
    int portNumber = 1337;
    Runnable r = () -> System.out.println(portNumber);
    portNumber = 31337;

3.6 方法引用

    //Lambda
    (Apple a) -> a.getWeight()
    //方法引用
    Apple::getWeight
    
    //Lambda
    () -> Thread.currentThread().dumpStack()
    //方法引用
    Thread.currentThread::dumpStack
    
    //Lambda
    (str, i) -> str.substring(i)
    //方法引用
    String::substring
    
    //Lambda
    (String s) -> System.out.println(s)
    //方法引用
    System.out.println

方法引用的三种类型

  1. 指向静态方法的方法引用
    • 比如 Integer 的 parseInt 方法,可以写作 Integer::parseInt
  //Lambda
  (args) -> ClassName.staticMethod(args)
  //方法引用
  ClassName::staticMethod
  1. 指向任意类型实例方法的方法引用
    • 比如 String 的 length 方法,可以写作 String::length
  //Lambda
  (arg0, rest) -> arg0.instanceMethod(rest)
  //方法引用
  ClassName::instanceMethod
  1. 指向现有对象的实例方法的方法引用
    • 比如你有一个局部变量 greenApple 用于存放 Apple 类型的对象,它支持实例方法 getColor,那么可以写作 greenApple::getColor
  //Lambda
  (args) -> expr.instanceMethod(args)
  //方法引用
  expr::instanceMethod

** 第二和第三的区别在于,第二个类型的方法引用是传递一个实例,这个实例会作为Lambda的参数;第三个方法则是在Lambda表达式外的已存在的对象。

** 一开始会有一些懵,可能因为是在方法引用里看不到函数所用的参数。实际上,因为是用已定义的方法来代替Lambda表达式传递到其他方法中,不需要再在这里显式参数;编译器会在运行时,自动根据签名来检查。函数的参数传递则在调用函数式接口的方法时,比如说 Predicate 的 test,参数通过test传递。

构造函数引用

    //若构造函数没有参数,Supplier的签名就适用;() -> T
    
    //这个引用指向默认的Apple构造函数
    Supplier<Apple> c1 = Apple::new
    Apple a1 = c1.get();
    
    //等价的Lambda表达式
    Supplier<Apple> c1 = () -> new Apple();
    Apple a1 = c1.get();
    //若构造函数有参数,Function的签名就适用;T -> R
    
    //这个引用指向Apple(Integer weight)的构造函数
    Function<Integer, Apple> c2 = Apple::new;
    Apple a2 = c2.apply(110);
    
    //等价的Lambda表达式
    Function<Integer, Apple> c2 = (weight) -> new Apple(weight);
    Apple a2 = c2.apply(110);

3.8 复合Lambda表达式

谓词复合

//用negate返回一个Predicate的非,比如苹果不是红的
Predicate<Apple> notRedApple = redApple.negate();
        
//用and串联两个方法,用来得到又红又大的苹果
Predicate<Apple> redAndHeavyApple = redApple.and( a -> a.getWeight() > 150);
        
//用or串联多个方法,等到结果要么是又红又大的苹果要么是绿苹果
Predicate<Apple> redAndHeavyApple = 
redApple.and( a -> a.getWeight() > 150)
        .or(a -> "green".equals(a.getColor()));

函数复合

Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2;
Function<Integer, Integer> h = f.andThen(g); //数学上写作 g(f(x))

int result = h.apply(1);
//结果为4
Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2;
Function<Integer, Integer> h = f.compose(g); //数学上写作 f(g(x))
        
int result = h.apply(1);
//结果为3
public class Letter{
    public static String addHeader(String text){
        return "From xxx : " + text;
    }
        
    public static String add addFooter(String text){
        return text + " Kind regards";
    }
        
    public static String checkSpelling(String text){
        return text.replaceAll("labda", "lambda");
    }
}
        
//Main
//创建一个流水线,给信加上抬头,检查拼写,再加上落款
Function<String, String> addHeader = Letter::addHeader; 
Function<String, String> transformationPipeline
    = addHeader.andThen(Letter::checkSpelling).andThen(Letter::addFooter);

Reference:

[1] Fusco, Mario, and Alan Mycroft. Java 8 in Action: Lambdas, Streams, and Functional-Style Programming. Manning, 2015.

上一篇下一篇

猜你喜欢

热点阅读