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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM