zoukankan      html  css  js  c++  java
  • JDK1.8新特性(二): Lambda表达式 (参数列表) -> { } 和函数式接口@FunctionalInterface

    Lambda表达式


    二:简介

    JDK的升级的目的有以下几个:增加新的功能、修复bug、性能优化、简化代码等几个方面,Lambda表达式就是属于简化代码,用于简化匿名实现类,提供一种更加简洁的写法。Lambda表达式在Swift语言中称之为代码块,Lambda表达式可以认为是一种特殊的接口,该接口必须只有一个抽象方法。

    语法

    (参数类型 参数名, 数参数类型 参数名2...) -> { 
    // code
    };

    小括号()中的内容就是方法中的参数列表包括参数类型、参数名,其中参数类型是可以省略的,当参数个数只有一个时也可以省略掉小括号;
    花括号{}中的内容就是方法中的方法体,当方法体中只有一行代码时可以省略{},当方法体中只有一行代码并且需要返回值时也可以省略掉return;
    由于Lambda表达式是匿名实现类的简写,是一种特殊的接口,当赋值给一个变量时也少不掉分号;

    Lambda表达式的作用

    • 简化匿名实现类的书写
    • 作为函数中的参数来传递

    二:示例

    示例1:两个参数,一个返回值

    IHello 一个很普通的接口,但接口中只能有一个抽象方法

    public interface IHello {
    String sayHello(String name, String msg);
    }

    Main

    public class Main {
    public static void main(String[] args) {
    // 将一个Lambda表达式赋值给一个接口,说明Lambda表达式就是一种接口数据类型,只不过该接口只能有一个抽象方法
    // 参数列表可以省略参数类型,可以写成(name, msg),
    // 在JDK1.8中有个叫做类型推断的东西,可以自动推断出参数的类型,
    // 因为IHello中只有一个抽象方法,知道方法了就知道参数列表了,从而就能推出参数类型来
    IHello iHello = (String name, String msg) -> {
    String hello = name + ": " + msg;
    return hello;
    };
    // 调用接口的方法
    String content = iHello.sayHello("mengday", "happy new year everyone!");
    System.out.println(content);
    }
    }

    示例2:一个参数,一个返回值

    public interface IHello {
    String sayHello(String name);
    }

    Main

    public class Main {
    public static void main(String[] args) {
    // 参数列表可以省略参数类型,当只有一个参数时可以省略小括号 (String name) --> (name) --> name
    // 当方法体中只有一行代码并且有返回值时可以同时省略花括号和return
    // { return name + ": " + "happy new year everyone!";} --> name + ": " + "happy new year everyone!";
    IHello iHello = name -> name + ": " + "happy new year everyone!";
    
    String content = iHello.sayHello("mengday");
    System.out.println(content);
    }
    }

    示例3:没有参数,没有返回值

    public interface IHello {
    void sayHello();
    }

    main

    public class Main {
    public static void main(String[] args) {
    // 当表达式没有参数时一对小括号是不能省略掉的
    IHello iHello = () -> System.out.println("mengday: happy new year everyone!");
    iHello.sayHello();
    }
    }


    从这三个示例中我们发现我们只定义了接口,并没有定义实现类,而是通过Lambda表达式来代替了实现类。
    注意:Lambda接口只能有一个抽象方法,可以同时拥有多个静态方法和默认方法。

    示例4:Lambda表达式参数

    public interface IHello { void sayHello(String name);
    }
    public class Main {
    
    public static void sayHello(IHello iHello, String name) {
    iHello.sayHello(name);
    }
    
    public static void main(String[] args) {
    
    IHello iHello = name -> {
    String content = name + ": " + "happy new year everyone!";
    System.out.println(content);
    };
    
    // 这里可以把iHelo看成一个匿名实现类来传递参数
    sayHello(iHello, "mengday");
    
    // 如果去掉变量的接收,直接将Lambda表达式传递到参数中,此时Lambda表达式更像是一个函数
    // 也就是说JDK1.8竟然可以将一个函数作为参数传递到方法中,这是之前版本做不到的
    // 将函数作为方法的参数传递,一般用于回调函数,将回调函数传递到方法中
    sayHello(name -> {
    String content = name + ": " + "happy new year everyone!";
    System.out.println(content);
    }, "mengday");
    }
    }

    示例5:集合排序示例

    public static void main(String[] args) {
    
    // 写法一:使用匿名内部类
    // 好好学习,天天向上
    List<String> words = Arrays.asList("good", "good", "study", "day", "day", "up");
    
    // public static <T> void sort(List<T> list, Comparator<? super T> c)
    Collections.sort(words, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
    // 降续排序
    return s2.compareTo(s1);
    }
    });
    
    System.out.println(words);
    // 写法二:使用Lambda表达式
    // 咱俩谁跟谁
    words = Arrays.asList("we", "two", "who", "and", "who");
    Collections.sort(words, (String s1, String s2) -> {return s2.compareTo(s1);});
    System.out.println(words);
    // 写法三:使用Lambda表达式(简写)
    // 有事起奏,无事退朝
    words = Arrays.asList("if", "you", "have", "something", "to", "say", "then", "say!",
    "if", "you", "have", "nothing", "to", "say", "go", "home!");
    Collections.sort(words, (s1, s2) -> s2.compareTo(s1));
    System.out.println(words);
    }

    函数式接口@FunctionalInterface

    从我们自定义的IHello示例来看,Lambda表达式其实是一种接口类型的数据类型,严格的说Lambda表达式的数据类型是:函数式接口,是一种特殊的接口,该接口使用@FunctionalInterface注解来标记(不是必须的,可以不用该注解标记,IHello接口就没有使用该注解标记, ),并且接口中只能有一个抽象方法,可以有多个静态方法或者默认方法, 每一个该类型的lambda表达式都会被匹配到这个抽象方法。

    @FunctionalInterface
    public interface Comparator<T> {
    int compare(T o1, T o2);
    // 其它static、default方法
    }

    @FunctionalInterface: 该注解没啥太大含义,该注解是给编译器做检查使用的,如果使用了该注解,编译器就会检查该接口中的抽象方法是不是只有一个,如果有多个就会报错:在接口Xxx中找到多个非覆盖抽象方法

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface FunctionalInterface {}

    我们完善一下我们的IHello, 使用@FunctionalInterface注解

    @FunctionalInterface
    public interface IHello {
    void sayHello(String name);
    }

    我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,也就是说我们的IHello接口无论叫什么名字,接口中的方法无论叫什么名字都无所谓(只是可读性更好些),因此可以再进行抽象化一下,JDK1.8中提供了这样的函数式接口,我们也不需要再定义IHello接口了,JDK1.8中提供了Supplier、Consumer、Function、BiFunction,这几个是比较常用的

    Supplier< T > 供应商:没有参数,有返回值

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

    Consumer< T > 消费者: 只有一个参数,没有返回值

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

    Function< T, R > 函数:一个参数,一个返回值

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

    BiFunction< T, U, R > 二元函数:两个参数,一个返回值

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

    Comparator< T > 比较器:接收两个参数,返回比较的结果

    @FunctionalInterface
    public interface Comparator<T> {
    int compare(T o1, T o2);
    }

    使用以上四大函数式接口来取代自定义的接口IHello

    public class Main {
    private static String end = ".";
    
    public static void main(String[] args) {
    // 直接使用JDK1.8提供的接口,不需要再定义IHello接口, 直接使用JDK提供的接口来接收Lambda表达式
    Supplier<String> supplier = () -> "mengday: happy new year everyone!";
    String result = supplier.get();
    System.out.println(result);
    
    Consumer<String> consumer = (name) -> System.out.println(name + ": " + "happy new year everyone!");
    consumer.accept("mengday");
    
    Function<String, String> func = (name) -> name + ": " + "happy new year everyone!";
    String hi = func.apply("mengday");
    System.out.println(hi);
    
    
    // 在代码块的内部可以访问静态全局变量
    // 在代码块中可以访问外边局部变量
    // 在代码块的内部可以修改全局静态变量
    // 在代码块内部是不能访问接口中的其它方法的
    String split = ": ";
    BiFunction<String, String, String> biFunction = (String name, String msg) -> {
    end = "!";
    String hello = name + split + msg + end;
    return hello;
    };
    String hello = biFunction.apply("mengday", "happy new year everyone");
    System.out.println(hello);
    
    // 根据字符串长度比较大小
    Comparator<String> comparator = (s1, s2) -> s1.length() - s2.length();
    int compare = comparator.compare("abc", "ab");
    System.out.println(compare);
    }
    }

    Predicate< T > 断言 谓词: 用于测试一个条件的真假

    package java.util.function;
    import java.util.Objects;
    
    @FunctionalInterface
    public interface Predicate<T> {
    // 在给定的参数上评估这个谓词
    boolean test(T t);
    
    // 返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND
    default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
    }
    
    // 返回表示此谓词的逻辑否定的谓词,相当于not
    default Predicate<T> negate() {
    return (t) -> !test(t);
    }
    
    // 返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑或
    default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
    }
    
    // 返回根据 Objects.equals(Object, Object)测试两个参数是否相等的谓词
    static <T> Predicate<T> isEqual(Object targetRef) {
    return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object);
    }
    }

    Main

    public static void main(String[] args) {
    // 可以构造复杂的条件: 并且and、或者or、否negate
    String email = "mengday@gmal.com";
    Predicate<String> predicate = (str) -> str.length() > 20;
    
    // 测试 emial.length > 0 的boolean
    boolean result = predicate.test(email); // false
    
    // 测试 !(emial.length > 0) 的boolean
    result = predicate.negate().test(email); // true
    
    Predicate<String> orPredicate = (str) -> str.contains("@");
    // 测试 emial.length > 0 or emial.contains("@")
    result = predicate.or(orPredicate).test(email); // true
    }

    参考文章:

    JDK1.8新特性(二): Lambda表达式 (参数列表) -> { } 和函数式接口@FunctionalInterface

  • 相关阅读:
    匈牙利算法-二分图的最大匹配
    UOJ 407(IOI2018 D1T3)
    UOJ 460
    UOJ 405(IOI2018 D1T1)
    Codeforces 1110E
    2.文件结构
    1.常用快捷键
    Python3.x和Python2.x的差异
    javascript 常用内置对象
    94. Binary Tree Inorder Traversal(非递归实现二叉树的中序遍历)
  • 原文地址:https://www.cnblogs.com/AlanWilliamWalker/p/11157374.html
Copyright © 2011-2022 走看看