• 行为参数化与lambda表达式


    零、 概述

    第一部分:1~3章 主要讲了行为参数化和Lambda表达式

    第二部分:4~7章 主要讲了流的应用,包括流与集合差异,流的操作,收集器,注的并行执行

    第三部分:8~12章 主要讲了怎样用Java8引入的特性改善老代码,Optional类和CompleteFuture及新的日期和时间API

    第四部分:13~16章 主要讲了函数式编程

    本文主要是对第一部分的笔记。

    一、行为参数化

    1.1 行为参数化定义

    行为参数化就是拿出一个代码块,把它准备好却不去执行它。

    1.2 举例:需求

    有个果农,有如下需求:

    1. 从仓库中找到红色苹果
    2. 找出所有重量超过150g的

    扩展一下:

    1. 可能以后还需要查找绿色苹果的功能
    2. 可能还需要找重量超过200g的

    1.3 举例:方案1

    传统实现方案

    // 筛选绿色苹果
    public static List<Apple> filterGreenApples(List<Apple> inventory) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if ("green".equals(apple.getColor())) {
                result.add(apple);
            }
        }
        return result;
    }
    
    // 可筛选任意颜色苹果,把颜色作为参数
    public static List<Apple> filterGreenApplesByColor(List<Apple> inventory, String color) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (apple.getColor().equals(apple.getColor())) {
                result.add(apple);
            }
        }
        return result;
    }
    // 筛选不同重量的苹果
    public static List<Apple> filterGreenApplesByWeight(List<Apple> inventory, int weight) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (apple.getWeight() > weight) {
                result.add(apple);
            }
        }
        return result;
    }
    
    // 写一个方法同时支持筛选颜色和重量
    public static List<Apple> filterGreenApples(List<Apple> inventory, String color, int weight
                , boolean filterColorFlag) {
    	List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if ((filterColorFlag && apple.getColor().equals(color))
                    || (!filterColorFlag && apple.getWeight() > weight)) {
                result.add(apple);
            }
        }
    	return result;
    }
    

    1.4 举例:方案2

    使用对象传递行为参数

    interface ApplePredicate {
        // 一个返回boolea值的函数,把它称为谓词
        boolean test(Apple apple);
    }
    
    // 筛选绿色
    public class AppleGreenColorPredicate implements ApplePredicate {
        @Override
        public boolean test(Apple apple) {
            return "green".equals(apple.getColor());
        }
    }
    
    // 重量大于150
    class AppleHeavyWeightPredicate implements ApplePredicate {
        @Override
        public boolean test(Apple apple) {
            return apple.getWeight() > 150;
        }
    }
    
    // 红色且重量大于150
    class AppleRedAndHeavyPredicate implements ApplePredicate {
        @Override
        public boolean test(Apple apple) {
            return "red".equals(apple.getColor()) && apple.getWeight() > 150;
        }
    }
    
    // 实现
    public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (p.test(apple)) {
                result.add(apple);
            }
        }
        return result;
    }
    
    public void test() {
        List<Apple> inventory = new ArrayList<>();
        // 筛选绿色
        filterApples(inventory, new AppleGreenColorPredicate());
    
        // 重量大于150
        filterApples(inventory, new AppleHeavyWeightPredicate());
    
        // 红色且重量大于150
        filterApples(inventory, new AppleRedAndHeavyPredicate());
    }
    

    1.5 举例:方案3

    使用匿名类传递行为参数

    // 对选择标准建模
    interface ApplePredicate {
        // 一个返回boolea值的函数,把它称为谓词
        boolean test(Apple apple);
    }
    
    // 实现
    public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (p.test(apple)) {
                result.add(apple);
            }
        }
        return result;
    }
    
    public static void main(String[] args) {
        List<Apple> inventory = new ArrayList<>();
        // 筛选绿色
        filterApples(inventory, new ApplePredicate() {
            @Override
            public boolean test (Apple apple){
                return "green".equals(apple.getColor());
            }
        });
    
        // 重量大于150
        filterApples(inventory, new ApplePredicate() {
            @Override
            public boolean test (Apple apple){
                return apple.getWeight() > 150;
            }
        });
    
        // 红色且重量大于150
        filterApples(inventory, new ApplePredicate() {
            @Override
            public boolean test (Apple apple){
                return "red".equals(apple.getColor()) && apple.getWeight() > 150;
            }
        });
    }
    

    1.6 举例:方案4

    使用Lambda表达式传递行为参数

    interface ApplePredicate {
        boolean test(Apple apple);
    }
    
    public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (p.test(apple)) {
                result.add(apple);
            }
        }
        return result;
    }
    
    public static void main(String[] args) {
        List<Apple> inventory = new ArrayList<>();
        // 筛选绿色
        filterApples(inventory
    		, (Apple apple) -> "green".equals(apple.getColor()));
    
        // 重量大于150
        filterApples(inventory
    		, (Apple apple) -> apple.getWeight() > 150);
    
        // 红色且重量大于150
        filterApples(inventory
    		, (Apple apple) -> "red".equals(apple.getColor()) && apple.getWeight() > 150);
    }
    

    在这里小结一下:

    2018-08-11_041102.png

    1.7 举例:方案5

    在方案4的基础上 将List类型抽象化

    // 定义一个函数式接口
    interface Predicate<T> {
        boolean test(T t);
    }
    
    // 定义一个调用函数式接口的方法
    public static <T> List<T> filter(List<T> list, Predicate<T> p) {
        List<T> result = new ArrayList<>();
        for (T e : list) {
            if (p.test(e)) {
                result.add(e);
            }
        }
        return result;
    }
    
    // 使用
    public static void main(String[] args) {
        List<Apple> inventory = FakeDb.getApples();
        List<Apple> redList = Filtering.filter(inventory
    		, (Apple apple) -> "red".equals(apple.getColor()));
    
        List<String> nonEmptyList = filter(Arrays.asList("1", "", "2")
    		, (String s) -> !s.isEmpty());
    }
    

    二、Lambda表达式

    2.1 Lambda表达式定义

    简洁地表示可传递的匿名函数的一种方法。

    • 匿名 {:&.fadeIn}
    • 函数
    • 传递
    • 简洁

    2.2 Lambda表达式长什么样子?

    下面是5个有效的Lambda表达式

    // 1 参数是String s,返回值是int
    (String s) -> s.length()
    
    // 2 参数是Apple a,返回值是boolean
    (Apple a) -> a.getWeight() > 150
    
    //  3 参数是int x,int y 没有返回值 {}内放语句,怎样区分语句与表达式
    (int x, int y) -> {
        System.out.println("Result:");
        System.out.println(x + y);
    }
    
    // 4 无参数,返回int
    () -> 42
    
    // 5 参数是两个Apple类型的变量,返回值是boolean
    (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())
    

    2.3 函数式接口

    函数式接口就是只定义一个抽象方法的接口。

    函数式接口的抽象方法的签名基本上就是Lambda表达式的签名,这种抽象方法叫做函数描述符

    一个注解:@FunctionalInterface ,不是必须的,用于表示该接口会设计成一个函数式接口

    2.4 Lambda的使用

    Predicate 过滤掉列表中的空串

    // 定义一个函数式接口
    interface Predicate<T> {
        boolean test(T t);
    }
    
    // 定义一个调用函数式接口的方法
    public static <T> List<T> filter(List<T> list, Predicate<T> p) {
        List<T> result = new ArrayList<>();
        for (T e : list) {
            if (p.test(e)) {
                result.add(e);
            }
        }
        return result;
    }
    
    // 使用
    public static void main(String[] args) {
        List<String> nonEmptyList = filter(Arrays.asList("1", "", "2")
    		, (String s) -> !s.isEmpty());
    }
    

    Consumer 计算列表中的每个元素的平方并输出

    @FunctionalInterface
    public interface Consumer<T> {
        void accept(T t);
    }
    
    public static <T> void forEach(List<T> list, Consumer<T> c) {
        for (T i : list) {
            c.accept(i);
        }
    }
    
    public static void main(String[] args) {
        forEach(Arrays.asList(1, 2, 3, 4), (Integer i) -> System.out.println(i * i));
    }
    

    Function** 返回列表中每个元素的长度

    @FunctionalInterface
    public interface Function<T, R> {
        R apply(T t);
    }
    
    public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
        List<R> result = new ArrayList<>();
        for (T s : list) {
            result.add(f.apply(s));
        }
        return result;
    }
    
    public static void main(String[] args) {
        List<Integer> result = map(Arrays.asList("1", "22", "333")
    		, (String s) -> s.length());
    }
    

    2.5 类型推断

    List<Apple> l = new ArrayList<Apple>();
    List<Apple> l = new ArrayList<>();
    
    // Java编译器根据Lambda出现的上下文来推断Lambda表达式参数的类型
    Predicate<Apple> p = (Apple a) -> 'red'.equals(a.getColor())
    Predicate<Apple> p = a -> 'red'.equals(a.getColor())
    

    2.6 方法引用

    主要为了简化代码

    方法引用,3种

    • 指向静态方法的方法引用 String.parseInt()
    • 指向实例方法的方法引用 str.length()
    • 指向外部对象实例方法的方法引用 globalVar.instanceMethod()
    List<String> strList = Arrays.asList("a", "b", "A", "B");
    strList.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
    strList.sort(String::compareToIgnoreCase); // 等效的方法引用
    

    构造函数引用

    Supplier<Apple> c1 = Apple::new; // 指向Apply()构造函数
    Apple a1 = c1.get();
    
    Function<Integer, Apple> c2 = Apple::new; // 指向Apply(int weight)构造函数
    Apple a2 = c2.apply(110);
    
    BigFunction<String, Integer, Apple> c3 = Apple::new;
    // 指向Apply(String color, Integer weight)
    Apple c3 = c3.apply("green", 110);
    

    2.7 Lambda实战

    根据Apple的重量来排序

    // 行为参数化,下面是通过不同方式传递这个行为的
    // 1.使用对象
    public class AppleComparator implements Comparator<Apple> {
        public int compare(Apple a1, Apple a2) {
            return a1.getWeight().compareTo(a2.getWeight());
        }
    }
    inventory.sort(new AppleComparator());
    
    // 2.使用匿名类
    inventory.sort(new Comparator<Apple>(){
        public int compare(Apple a1, Apple a2) {
            return a1.getWeight().compareTo(a2.getWeight());
        }
    });
        
    // 3.使用Lambda表达式
    inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
    // 因为类型推断,可以简化成
    inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
    // 因为有个java.util.Comparator.comparing静态方法,还可以简化成
    import static java.util.Comparator.comparing;
    inventory.sort(comparing((a) -> a.getWeight()));
    
    // 4.使用方法引用
    inventory.sort(comparing(comparing(Apple::getWeight)));
    

    2.8 复合Lambda表达式

    比较器复合

    // 逆序,苹果按重量递减排序
    inventory.sort(comparing(Apple::getWeight).reversed());
    
    // 比较器链,先按重量递减排序再按国家排序
    inverntory.sort(comparing(Apple::getWeight).reversed()
                   .thenComparing(Apple::getCountry));
    

    谓词复合

    // negate,and,or
    // 筛选不是红苹果
    Predicate<Apple> notRedApple = redApple.negate();
    // 筛选红苹果且重量大于150   或  绿苹果
    redApple.and(a -> a.getWeight() > 150).or(a -> "green".equals(a.getColor()));
    
    // a.or(b).and(c) <==> (a || b) && c
    

    函数复合

    // andThen,compose
    
    Function<Integer, Integer> f = x -> x + 1;
    Function<Integer, Integer> g = x -> x * 2;
    
    // g(f(x))
    Function<Integer, Integer> h = f.andThen(g);
    int result = h.apply(1);
    
    // f(g(x))
    Function<Integer, Integer> h = f.compose(g);
    int result = h.apply(1);
    

    三、代码

    https://gitee.com/yysue/tutorials-java/tree/master/java-8

  • 相关阅读:
    如何让SAP S/4HANA的Material Fiori应用配置到Fiori Launchpad里
    SAP S/4HANA扩展字段创建过程的单步调试
    SAP S/4HANA扩展字段创建过程的单步调试
    使用ABAP代码创建SAP S/4HANA系统的扩展字段
    SAP Fiori里的Adapt UI按钮,神出鬼没的奥秘
    一步步把SAP GUI的事务码配置到SAP Fiori Launchpad里
    揭开SAP Fiori编程模型规范里注解的神秘面纱
    再谈OPENCV(转)
    JAVA随笔(二)
    计算机视觉数据集
  • 原文地址:https://www.cnblogs.com/okokabcd/p/9463101.html
Copyright © 2020-2023  润新知