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 }