zoukankan      html  css  js  c++  java
  • java8 lambda表达式和函数型接口

      1 /**
      2  * @author gc
      3  * Lambda  表达式的基础语法:java8中引入一个新的操作符 "->" ,该操作符称为箭头操作符或lambda操作符
      4  *      箭头操作符将lambda拆分成两部分:
      5  *      左侧:lambda表达式的参数列表
      6  *      右侧:lambda表达式中所需执行的功能,即lambda体
      7  *  语法格式一:无参数,无返回值
      8  *      () -> System.out.println("xxxxxx");
      9  *  语法格式二:有一个参数,无返回值
     10  *      (x) -> System.out.println(xxxxxx);
     11  *  语法格式三:若只有一个参数,小括号可以省略不写
     12  *      x -> System.out.println(x);
     13  *  语法格式四:有两个以上的参数,有返回值,并且lambda体中有多条语句    test4
     14  *      Comparator<Integer> comparator = (x,y) -> {
     15  *            System.out.println("函数式接口");
     16  *            return Integer.compare(x, y);
     17  *        };
     18  *    语法格式五:若lambda体中只有一条语句,则return和大括号都可以省略不写
     19  *        Comparator<Integer> comparator = (x,y) -> Integer.compare(x, y);
     20  *    语法格式六:lambda表达式的参数列表的数据类型可以省略不写,因为jvm编译器可以根据上下文推断出数据类型,即“类型推断”
     21  *        (Integer x,Integer y) -> Integer.compare(x, y);  == (x,y) -> Integer.compare(x, y);
     22  *    
     23  *    左右遇一括号省(左边是一个参数或者右边只有一条语句), 左侧推断类型省(左边不需要显示指定类型)
     24  *
     25  *    二、lambda表达式需要函数式接口的支持
     26  *        函数式接口:接口中只有一个抽象方法的接口(这样才知道要动态替换哪个方法),可以使用 @FunctionalInterface 检查一下
     27  *        反而言之:jdk接口上有@FunctionalInterface注解的都是函数式接口
     28  */
     29 public class TestLambda {
     30     
     31     @Test
     32     public void test1() {
     33         new Thread(new Runnable() {
     34             @Override
     35             public void run() {
     36                 Runnable r1 = () -> System.out.println("hello lambda1");
     37             }
     38         }).start();
     39         
     40         //相当于实现接口Runable无参方法run的匿名实现类.这里的实现同上面的匿名类效果一样
     41         Runnable r1 = () -> System.out.println("hello lambda2");
     42         new Thread(r1).start();
     43     }
     44     @Test
     45     public void test2() {
     46         //这里因为是一个参数,所以左边的括号省略,右边是一个表达式,所以右边的大括号省略
     47         //Consumer是一个消费者型的函数式接口,其accept方法可以对接收到的数据进行处理。这里相当于实现其抽象方法accept
     48         Consumer<String> consumer = x -> System.out.println(x);
     49         consumer.accept("我很帅");
     50     }
     51     
     52     @Test
     53     public void test4() {
     54         //这里左边是两个参数,所以使用括号,右边是两条语句,使用大括号。这里是实现了Comparator接口的compare方法,用于collection排序操作
     55         Comparator<Integer> comparator = (x,y) -> {
     56             System.out.println("函数式接口");
     57             return Integer.compare(x, y);
     58         };
     59         //这里是简写,效果同上
     60         Comparator<Integer> comparator2 = (x,y) -> Integer.compare(x, y);
     61     }
     62     
     63     //通过这里的两个lambda实现,可以发现函数式接口的方法是动态改变的,而且不用继续接口,不用匿名类,实现起来方便快捷
     64     @Test
     65     public void test5() {
     66         //(x) -> (x + 1)是一个lambda表达式,功能是自增。
     67         //其相当于一个入参和返回值类型相同的函数,这里将其传给MyFun<Integer>,可以作为函数式接口MyFun内方法getValue的实现。
     68         //可以理解为MyFun内方法getValue的实现变成了整数值自增然后返回
     69         Integer result = operation(100, (x) -> (x + 1));
     70         //这里输出101
     71         System.out.println(result);
     72         //这里同理,只是getValue的实现变成了自减,所以输出结果为99
     73         System.out.println(operation(100, (x) -> (x - 1)));
     74     }
     75     public Integer operation(Integer num, MyFun<Integer> mf) {
     76         return mf.getValue(num);
     77     }
     78 
     79     List<User> users = Arrays.asList(
     80             new User("gc", 24, 7500),
     81             new User("gc", 25, 13000),
     82             new User("gc", 26, 20000));
     83     
     84     @Test
     85     public void test6() {
     86         //这里第二个参数是lambda表达式,其实现了函数表达式式Comparator的compare方法
     87         Collections.sort(users, (u1, u2) -> {
     88             return u1.getAge() - u2.getAge();
     89         });
     90         System.out.println(users);
     91     }
     92     @Test
     93     //对两个long型进行处理
     94     public void test7() {
     95         //参数3是lambda,用于实现函数式接口。相当于MyFun2的getValue(a,b)功能变成了a+b
     96         op(100L, 200L, (x,y) -> x + y);
     97     }
     98     public void op(Long t1, Long t2, MyFun2<Long, Long> mf2) {
     99         System.out.println(mf2.getValue(t1, t2));
    100     }
    101     @Test
    102     public void test() {
    103         //这里是stream配合lambda表达式一起使用。stream这里简单理解为遍历list
    104         //(e) -> e.getSalary() >= 10000是函数式接口Predicate内方法test的实现,其功能是判断是否正确
    105         //下面这里就是判断list中的元素的salary是否大于10000,大于的继续往下处理
    106         //forEach就是遍历打印。这里总体的功能就是遍历list,打印salary大于10000的User
    107         users.stream().
    108             filter((e) -> e.getSalary() >= 10000).forEach(System.out::println);
    109         users.stream().
    110             map((e) -> e.getName()).forEach(System.out::println);
    111     }
    112 }
    1 @FunctionalInterface
    2 public interface MyFun<T> {
    3     
    4     public T getValue(T value);
    5 }
    1 @FunctionalInterface
    2 public interface MyFun2<T, R> {
    3     
    4     public R getValue(T t1, T t2);
    5 }
     1 public class User {
     2     private String name;
     3     private int age;
     4     private int salary;
     5     private Status status;
     6     
     7     @Override
     8     public String toString() {
     9         return "User [name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status + "]";
    10     }
    11 
    12     public User(String name, int age, int salary) {
    13         super();
    14         this.name = name;
    15         this.age = age;
    16         this.salary = salary;
    17     }
    18 }    
     1 /**
     2  * @author gc、
     3  * java8 内置的四大核心函数式接口
     4  * 
     5  * Consumer<T>: 消费型接口,接收数据并处理
     6  *         void accept(T t);
     7  * Supplier<T>: 供给型接口,对外提供数据
     8  *         T get()
     9  * Function<T, R>: 函数型接口,接收参数,返回结果
    10  *         R apply(T t);
    11  * Predicate<T>: 断言型接口,检测入参是否符合条件(符合则返回true)
    12  *         boolean test(T t);
    13  *
    14  */
    15 public class TestLambdaFunc {
    16 
    17     @Test
    18     //Consumer<T> 消费型接口
    19     public void testConsumer() {
    20         //Consumer是消费型接口,其可定义对接收到的数据进行不同的处理。这里的处理方式就是打印详细信息。
    21         //m -> System.out.println("大保健,消费:"+m+" 元") 可以理解为Consumer中accept(T t)方法的实现
    22         happy(10000L, m -> System.out.println("大保健,消费:"+m+" 元"));
    23     }
    24     public void happy(double money, Consumer<Double> con) {
    25         con.accept(money);
    26     }
    27     
    28     //Supplier<T> 供给型接口
    29     @Test
    30     public void testSupplier() {
    31         //Supplier是供给型接口。其内部定义对外输出的数据。而且不需要入参
    32         //() -> (int)(Math.random() * 100) 为这里的供给行为,即返回一个随机数
    33         List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
    34         System.out.println(numList);
    35     }
    36     
    37     public List<Integer> getNumList(int num, Supplier<Integer> sup) {
    38         List<Integer> list = new ArrayList<>();
    39         
    40         for (int i = 0; i < num; i++) {
    41             Integer n = sup.get();
    42             list.add(n);
    43         }
    44         return list;
    45     }
    46     
    47     //Function<T,R> 函数型接口
    48     @Test
    49     public void testFunction() {
    50         //函数型接口功能相对强大,可以对接收到的数据进行进一步处理,返回类型可以和入参类型不一致(泛型接口,二元组)
    51         //(x) -> (x + ", 哈哈哈") 这里作为Function接口中apply的实现
    52         String str = strHandler("我最帅", (x) -> (x + ", 哈哈哈"));
    53         System.out.println(str);
    54     }
    55     private String strHandler(String str, Function<String, String> fun) {
    56         return fun.apply(str);
    57     }
    58     
    59     //Predicate<T> 断言型接口
    60     @Test
    61     public void testPredicate() {
    62         List<String> list = Arrays.asList("Hello", "World", "www.exact.com");
    63         //函数式接口Predicate主要用于判断,x -> (x.length() > 5) 这里是判断入参的长度是否大于5
    64         List<String> filterStr = filterStr(list, x -> (x.length() > 5));
    65         System.out.println(filterStr);
    66     }
    67     
    68     public List<String> filterStr(List<String> list, Predicate<String> pre) {
    69         List<String> strList = new ArrayList<>();
    70         
    71         for (String str : list) {
    72             if(pre.test(str)) {
    73                 strList.add(str);
    74             }
    75         }
    76         return strList;
    77     }
    78 }
     1 /**
     2  * @author gc
     3  * 方法引用:若lambda体中的内容有方法已经实现了,我们可以使用“方法引用”
     4  *         (可以理解为方法引用是lambda表达式的另外一种表达形式)
     5  * 主要有三种语法格式:
     6  *         对象::实例方法名
     7  *         类::静态方法名
     8  *         类::实例方法名
     9  * 注意:
    10  *     1.lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型一致
    11  *  2.若lambda参数列表 中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用className::method
    12  *  
    13  *  二、构造器引用
    14  *  格式:
    15  *      ClassName::new
    16  */
    17 public class TestMethodRef {
    18 
    19     
    20     //对象::实例方法名
    21     @Test
    22     public void test() {
    23         Consumer<String> consuemr = (x) -> System.out.println(x);
    24         consuemr.accept("aaaa");
    25         
    26         PrintStream ps = System.out;
    27         Consumer<String> consumer2 = ps::println;
    28         consumer2.accept("asdf");
    29     }
    30     
    31     @Test
    32     public void test2() {
    33         User user= new User("gc",20,200000);
    34         //这里是无参,所以左边使用了()
    35         Supplier<String> sup = () -> user.getName();
    36         System.out.println(sup.get());
    37         
    38         //这里对lambda表达式进行了省略。() -> user.getAge() == user::getAge
    39         Supplier<Integer> sup2 = user::getAge;
    40         System.out.println(sup2.get());
    41     }
    42     
    43     //类::静态方法名
    44     public void test3() {
    45         Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
    46         
    47         //这里因为入参和lambda实现方法要调用的入参一样。所以两边都省略了
    48         Comparator<Integer> com1 = Integer::compare;
    49     }
    50     
    51     //类::实例方法名
    52     public void test4() {
    53         BiPredicate<String, String> bp = (x,y) -> x.equals(y);
    54         
    55         //这里是两个入参,而且满足第一个参数是新方法调用者,第二个参数是入参的情况
    56         //理论而言都用上面的表达式即可,看起来比较简单,但是不能避免别人不会使用简写方式,看不懂岂不是很尴尬
    57         BiPredicate<String, String> bp2 = String::equals;
    58     }
    59     
    60     @Test
    61     public void test5() {
    62         //函数式接口生产数据的方式是new User();
    63         Supplier<User> sup = () -> new User();
    64         //这里功能同上,简写方式
    65         Supplier<User> sup2 = User::new;
    66         System.out.println(sup2.get());
    67     }
    68 }
  • 相关阅读:
    昨天是下了一整天的雨,在家里买了一斤肉和恶小白菜吃
    昨天网上感觉好冷,睡在席子上都是感觉打哈欠
    今天是下雨了,看来是要穿长裤上班了
    昨天用的流量有点多60M
    Python常用模块(3)—— shelve、pickle、json、xml、configparser
    Python常用模块(2)—— os、sys、shutil
    Python常用模块(1)—— time、datetime、randrom
    内置函数
    包的导入使用
    模块的导入使用
  • 原文地址:https://www.cnblogs.com/gc65/p/10604616.html
Copyright © 2011-2022 走看看