深入浅出理解Java Lambda表达式之四大核心函数式的用法与范例
作者:张起灵-小哥
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑,今天小编带你理解Lambda表达式之四大核心函数式的用法,感兴趣的朋友快来看看吧
1.四大核心函数式接口
上一篇文章中说到了Lambda表达式中的基本语法,以及我们如何自定义函数式接口。但是在写代码的过程中,大家可能会发现一个问题:当我们有一个新的需求时,可以去自定义一个函数式接口,然后再创建一个它的实现类定义一些相关的业务逻辑行为。那么如果说我们有很多需求、这些需求可能还会不断地变化,那么我们岂不是每次都要去创建新的实现类、同时再去修改之前创建好的实现类中的业务代码?这可太麻烦了吧。。。
所以呢,Java8就为我们提供了四大核心函数式接口,使用起来非常的方便。
1.1 Consumer<T> : 消费型接口
package com.szh.java8; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; /* * */ public class MyTest3 { //Consumer<T> : 消费型接口 @Test public void test1() { happy(6666.66,(m) -> System.out.println("本地双11共消费 " + m + " 元!!!")); } public void happy(double money, Consumer<Double> consumer) { consumer.accept(money); } }
1.2 Supplier<T> : 供给型接口
package com.szh.java8; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; /* * */ public class MyTest3 { //Supplier<T> : 供给型接口 @Test public void test2() { List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100)); for (Integer num : numList) { System.out.println(num); } } public List<Integer> getNumList(int num, Supplier<Integer> supplier) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < num; i++) { Integer n = supplier.get(); list.add(n); } return list; } }
1.3 Function<T, R> : 函数型接口
package com.szh.java8; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; /* * */ public class MyTest3 { //Function<T, R> : 函数型接口 @Test public void test3() { String trimStr = strHandler("\t\t\t 张起灵-小哥 ", (str) -> str.trim()); System.out.println(trimStr); String newStr = strHandler("我喜欢看盗墓笔记呀!!!",(str) -> str.substring(4,8)); System.out.println(newStr); } public String strHandler(String str, Function<String,String> function) { return function.apply(str); } }
1.4 Predicate<T> : 断言型接口
package com.szh.java8; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; /* * */ public class MyTest3 { //Predicate<T> : 断言型接口 @Test public void test4() { List<String> list = Arrays.asList("Hello","张起灵-小哥","HashMap","jdk8","List","Set"); List<String> stringList = filterStr(list, (s) -> s.length() > 5); for (String string : stringList) { System.out.println(string); } } public List<String> filterStr(List<String> strings, Predicate<String> predicate) { List<String> strList = new ArrayList<>(); for (String str : strings) { if (predicate.test(str)) { strList.add(str); } } return strList; } }
除此之外,还有一些其他的函数式接口,它们有一部分是上面提到的四大核心函数式接口的子接口。
2.方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用! 方法引用:使用操作符 “ :: ” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况 :
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
可以将方法引用理解为 Lambda 表达式的另外一种表现形式,方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
2.1 对象 :: 实例方法
@Test public void test1() { Consumer<String> con1 = (str) -> System.out.println(str); con1.accept("Hello World!!!"); PrintStream ps = System.out; Consumer<String> con2 = ps::println; con2.accept("Hello Java8!!!"); Consumer<String> con3 = System.out::println; con3.accept("Hello Lambda!!!"); }
@Test public void test2() { Employee emp = new Employee(); emp.setName("张起灵"); emp.setAge(18); Supplier<? extends Object> sup1 = () -> emp.getName(); String str = (String) sup1.get(); System.out.println(str); Supplier<Integer> sup2 = emp::getAge; Integer age = sup2.get(); System.out.println(age); }
package com.szh.java8; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * */ @Data @NoArgsConstructor @AllArgsConstructor public class Employee { private Integer id; private String name; private Integer age; private Double salary; public Employee(Integer id) { this.id = id; } public Employee(Integer id,String name) { this.id = id; this.name = name; } }
2.2 类 :: 静态方法
@Test public void test3() { Comparator<Integer> com1 = (x,y) -> Integer.compare(x,y); System.out.println(com1.compare(10, 20)); Comparator<Integer> com2 = Integer::compare; System.out.println(com2.compare(300, 110)); }
2.3 类 :: 实例方法
若 Lambda 的参数列表的第一个参数是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
@Test public void test4() { BiPredicate<String,String> bp1 = (str1,str2) -> str1.equals(str2); System.out.println(bp1.test("Hello", "hello")); BiPredicate<String,String> bp2 = String::equals; System.out.println(bp2.test("Java", "Java")); }
3.构造器引用
格式 : ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。构造器的参数列表,需要与函数式接口中参数列表保持一致!
代码中Employee类参考上面的案例。
@Test public void test5() { //无参构造器 Supplier<Employee> sup1 = () -> new Employee(); System.out.println(sup1.get()); //无参构造器 Supplier<Employee> sup2 = Employee::new; System.out.println(sup2.get()); //一个参数构造器 Function<Integer,Employee> function = Employee::new; Employee employee = function.apply(1001); System.out.println(employee); //两个参数构造器 BiFunction<Integer,String,Employee> biFunction = Employee::new; Employee emp = biFunction.apply(1001, "张起灵"); System.out.println(emp); }
4.数组引用
格式 :类型[] :: new
@Test public void test6() { Function<Integer,String[]> fun = (x) -> new String[x]; String[] strings = fun.apply(10); System.out.println(strings.length); Function<Integer,String[]> fun2 = String[]::new; String[] strArray = fun2.apply(50); System.out.println(strArray.length); }
以上就是深入浅出理解Java Lambda表达式之四大核心函数式的用法与范例的详细内容,更多关于Java Lambda表达式的资料请关注脚本之家其它相关文章!