美文网首页
lambda及函数式接口

lambda及函数式接口

作者: keyuan0214 | 来源:发表于2020-01-09 10:37 被阅读0次

    一、lambda是什么

    • 函数式编程?匿名内部类?简洁?
    • 来源于学术界λ,主要是行为参数化、简化内部类,在函数式接口中应用广泛。

    二、为什么要学习lambda?

    • 本文让你彻底学会使用lambda,不管在哪里你都能()->{} 一把嗦。

    三、lambda语法

    • 一个完整的lambda表达式
    (Type1 param1,Type2 param2,Type3 params)->{
    
        statement1;
        statement2;
        ....
        return data;
    }
    复制代码
    

    1、()->{},lambda参数、箭头、lambda主体缺一不可

    2、参数类型可以省略,而且基本都是省略

    3、lambda主体中如果只有一条语句可以省略大括号、return及结尾分号

    4、方法引用可以作为lambda表达式

    无参lambda

    • 比匿名内部类更先进,接口名称、函数名都省略了。
    • lambda体只有一行,{}可以省略。
    image.png

    有参lambda

    • 很多时候idea都能优化,但是但是。。。提交的代码库中依然一堆idea提示灰色。
    image.png

    四、 函数式接口

    • 能够使用lambda的依据是函数式接口,即内部只有一个抽象方法的接口,并非只有一个方法。
    • lambda表达式的类型推断也是跟函数式接口有关,编译器能根据上下文信息推断出参数类型。

    几个典型的函数式接口

    1、BiFunction

    @FunctionalInterface
    public interface BiFunction<T, U, R> {
        R apply(T t, U u);
    
        default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (T t, U u) -> after.apply(apply(t, u));
        }
    }
    复制代码
    

    1、这个函数式接口在java 8 stream中大量使用。

    2、有2个方法,只有1个抽象方法

    3、抽象方法apply接受2个参数,类型是T,U,返回值是R。

    4、下面的get()第三个参数的BiFunction函数式接口,因此你在调用get()可以传递一个符合该函数式接口规范的lambda。至于参数1、参数2怎么操作、运算、加密。。。依赖于你的lambda主体。

    image.png

    2、Consumer

    • 消费函数,返回值为void。
    
    @FunctionalInterface
    public interface Consumer<T> {
        void accept(T t);
    
        default Consumer<T> andThen(Consumer<? super T> after) {
            Objects.requireNonNull(after);
            return (T t) -> { accept(t); after.accept(t); };
        }
    }
    
    复制代码
    
    • 返回值void,故一般使用其副作用。
    image.png

    3、Predicate

    • 断言/条件测试,定义一个抽象方法,必定有1个入参,返回值boolean。
    • 最常用在stream中的filter(),可以组成predicate调用链。
    //以下都可以做一个Predicate的lambda
    1、(s)->s.length()>0;
    2、(v)->v > 100;
    3、(o)->o.startWith("a");
    
    复制代码
    

    4、Supplier

    • 不需要输入,产出T。像是一个容器,调用get返回对象。
    Supplier<Integer> supplier = new Supplier<Integer>() {
                @Override
                public Integer get() {
                    //返回一个随机值
                    return new Random().nextInt();
                }
            };
    System.out.println(supplier.get());
    System.out.println(supplier.get());
    复制代码
    

    方法引用

    • 简单来讲就是让你可以重复使用现有的方法定义,并像lambda一样传递他们,使用::来表示。主要有三类。
    • 核心点:函数签名要符合,即传参类型、参数数量、返回值类型还是void。

    1、静态方法的方法引用

    • 静态方法作用于对象上。
      public static void main(String[] args) {
        List<String> list = Lists.newArrayList("1","2","3","4");
    
        List<Integer> collect1 = list.stream().map(v -> Integer.parseInt(v))
            .collect(Collectors.toList());
        List<Integer> collect2 = list.stream().map(Integer::parseInt)
            .collect(Collectors.toList());
    
      }
    复制代码
    

    2、指向 任意类型实例方法 的方法引用

    1、这个任意类型一般指的是你的lambda的入参类型。

    2、如下面的入参是v,调用v.length可以写作v的类型String::length。

      public static void main(String[] args) {
    
        List<String> list = Lists
            .newArrayList("hello", "how", "are", "you", "i", "am", "fine", "thank", "you", "and",
                "you");
        Set<Integer> collect = list.stream().map(v -> v.length()).collect(Collectors.toSet());
    
        Set<Integer> collect1 = list.stream().map(String::length).collect(Collectors.toSet());
        System.out.println(collect);
        System.out.println(collect1);
      }
    复制代码
    

    3、指向既有对象的方法的方法引用

    • 与上述第2点类似,不详细说明。

    五、小结

    • 主要介绍了lambda表达式及函数式接口
    • 使用函数式接口的核心就是搞对函数签名,传入一个符合条件签名的lambda,就可以()->{}一把唆了。

    相关文章

      网友评论

          本文标题:lambda及函数式接口

          本文链接:https://www.haomeiwen.com/subject/foqyactx.html