zoukankan      html  css  js  c++  java
  • Lambda表达式

    函数式接口

    Predicate

    @FunctionalInterface
    public interface Predicate<T> {
    
        /**
         * Evaluates this predicate on the given argument.
         *
         * @param t the input argument
         * @return {@code true} if the input argument matches the predicate,
         * otherwise {@code false}
         */
        boolean test(T t);
    ...
    }

    可以看到实际上Predicate只有一个需要显示实现的方法,所以可以用@FunctionalInterface,它是一个函数式接口。

    示例

    public class Bear {
    
        private String color;
    
        public Bear(String color) {
            this.color = color;
        }
    
        public static List<Bear> filter(List<Bear> bears, Predicate<Bear> predicate) {
            List<Bear> bears1 = new ArrayList<>();
            for (Bear bear : bears) {
                if (predicate.test(bear)) {
                    bears1.add(bear);
                }
            }
            return bears1;
        }
    
        public String getColor() {
            return color;
        }
    
        public void setColor(String color) {
            this.color = color;
        }
        
        public static void main(String[] args) {
            filter(List.of(new Bear("green"), new Bear("red")), (Bear b) -> b.getColor().equals("red"));
        }
    }

    Consumer

    @FunctionalInterface
    public interface Consumer<T> {
    
        /**
         * Performs this operation on the given argument.
         *
         * @param t the input argument
         */
        void accept(T t);
    ...
    }

    Consumer翻译就是消费者了,所以可以理解为这个接口的作用是消费对象,因此可以看到它是void的

    示例

    public class Bear {
    
        private String color;
    
        public Bear(String color) {
            this.color = color;
        }
    
        public static List<Bear> forEach(List<Bear> bears, Consumer<Bear> consumer) {
            List<Bear> bears1 = new ArrayList<>();
            for (Bear bear : bears) {
                consumer.accept(bear);
            }
            return bears1;
        }
    
        public String getColor() {
            return color;
        }
    
        public void setColor(String color) {
            this.color = color;
        }
    
        public static void main(String[] args) {
            forEach(List.of(new Bear("green"), new Bear("red")), 
                    (Bear bear) -> System.out.println(bear.getColor()));
        }
    }

    Function

    @FunctionalInterface
    public interface Function<T, R> {
    
        /**
         * Applies this function to the given argument.
         *
         * @param t the function argument
         * @return the function result
         */
        R apply(T t);
    ...
    }

    这个接口就是接受一个T类型的对象,映射返回一个R类型的对象。

    示例

    public class Bear {
        public static <T, R> List<R> map(List<T> bears, Function<T, R> function) {
            List<R> list = new ArrayList<>();
            for (T t : bears) {
                list.add(function.apply(t));
            }
            return list;
        }
    
        public static void main(String[] args) {
            List<Integer> list = map(List.of("aa", "aas", "sssss"), (String s) -> s.length());
            list.stream().forEach((s) -> System.out.println(s.intValue()));
        }
    }

    以上是三个标准的泛型化接口,为什么要设计成引用类型呢,因为泛型不允许和原始类型一块使用。当然这个问题也不是这么简单的解释。

    类型推断

    list.stream().forEach(s -> System.out.println(s.intValue()));

    这行代码并没有定义s的类型,但是它是会进行上下文判断的。

    使用局部变量

            int num = 22;
            Runnable r = () -> System.out.println(num);       ok
            int num = 22;
            Runnable r = () -> System.out.println(num++);      error
            int num = 22;
            Runnable r = () -> System.out.println(num);        error
            num++;

    lambda中是不允许修改其引用值的。

    实际上我之前研究过,此处就是单纯的copy by value, not copy by reference.对比其它的语言,这无疑是一大败笔,当然会改善,但是不知道什么时候,希望尽快,它是个灾难。

    lambda可以没有限制的捕获实例变量或者静态变量,但是局部变量必须显示的声明为final,或者不声明但是实际上是final,lambda捕获的局部变量必须是最后一次赋值完成的。

    方法引用

    inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())); 
    inventory.sort(comparing(Apple::getWeight)); 

     方法引用的三类:

    指向静态方法的引用:Integer中的parseInt方法,写作Integer::parseInt

    指向任意类型实例方法的方法引用:String::length

    指向现有对象的实例方法引用:下面分析

    第二种就是你在引用对象的方法,比如,(String s) -> s.toUpperCase()就可以写成 String::toUpperCase

    第三种就是调用外部对象的方法,比如 () -> expenseiveTransaction.getValue() 就可以写成 expensiveTransaction::getValue,  这种也是较为常用的

    举个常用的例子,比如你要对List<String>进行排序,可以这样:

            List<String> list = Arrays.asList("a", "v", "c");
            list.sort((s1, s2) -> s1.compareToIgnoreCase(s2));

    也可以只方法引用:

            list.sort(String::compareToIgnoreCase);

    构造函数引用

            Supplier<Apple> c1 = () -> new Apple();
            Apple apple = c1.get();

    等效于:

            Supplier<Apple> c1 = Apple::new;
            Apple apple = c1.get();

    多参数的构造器

            BiFunction<String, Integer, Apple> c1 = (color, weight) -> new Apple(color, weight);      这里一个细节就是你需要将要创建的对象放在泛型的尾部
            BiFunction<String, Integer, Apple> c2 = Apple::new;

    一个示例应用,大概就是根据苹果类型和重量新建苹果对象

        public Apple(int weight) {
            this.weight = weight;
        }
    
        static Map<String, Function<Integer, Apple>> map = new HashMap<>();
        static {
            map.put("apple1", Apple::new);
            map.put("apple2", Apple::new);
        }
        public static Apple giveMeApple(String appleType, Integer weight) {
            return map.get(appleType.toLowerCase()).apply(20);
        }

    复合Lambda表达式

    比较器复合

    逆序

            apples.sort(Comparator.comparing(Apple::getWeight).reversed());

    比较器链

            apples.sort(Comparator.comparing(Apple::getWeight)
                    .reversed()
                    .thenComparing(Apple::getColor)    // 如果两个Apple一样重,那么再比较颜色,当然这里用颜色比较是不合适的
            );

    谓词复合

    函数复合

        public static void main(String[] args) {
            Function<Integer, Integer> f = x -> x + 1;
            Function<Integer, Integer> g = x -> x * 2;
            Function<Integer, Integer> h = f.andThen(g);
            System.out.println(h.apply(1));
        }
    输出4

    andThen实际上是 g(f(x))

        public static void main(String[] args) {
            Function<Integer, Integer> f = x -> x + 1;
            Function<Integer, Integer> g = x -> x * 2;
            Function<Integer, Integer> h = f.compose(g);
            System.out.println(h.apply(1));
        }
    输出3

    compose实际上是f(g(x))

     这种函数复合有什么用呢?

    小结

     

     《Java8实战》

     
    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    CodeForces 173B Chamber of Secrets spfa
    CodeForces 173A Rock-Paper-Scissors 数学
    Codeforces Gym 100803G Flipping Parentheses 线段树+二分
    Codeforces Gym 100803D Space Golf 物理题
    Codeforces Gym 100803F There is No Alternative 暴力Kruskal
    Codeforces Gym 100803C Shopping 贪心
    《白日梦想家》观后感
    select sum也会返回null值
    mysql update更新带子查询的实现方式
    mysql 添加索引 mysql 如何创建索引
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12121563.html
Copyright © 2011-2022 走看看