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 }