lambda之常用函数式接口
函数式接口和lambda表达式关联
函数式接口只能操作一个方法,而λ表达式也只能操作一个方法,λ表达式其实核心就是一个函数式接口的实现。
正常创建订单和匿名创建订单
订单类
package liojx.kn.fnI; import java.math.BigDecimal; import java.util.Date; public class Order { /** 订单编号 */ private String orderCode; /** 订单创建时间 */ private Date createTime; /** 订单总价 */ private BigDecimal totalPrice; /** 商品数量 */ private int count; /** 商品 */ private String product; public Order() { } public Order(String orderCode, Date createTime, BigDecimal totalPrice, int count, String product) { this.orderCode = orderCode; this.createTime = createTime; this.totalPrice = totalPrice; this.count = count; this.product = product; } public String getOrderCode() { return orderCode; } public void setOrderCode(String orderCode) { this.orderCode = orderCode; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public BigDecimal getTotalPrice() { return totalPrice; } public void setTotalPrice(BigDecimal totalPrice) { this.totalPrice = totalPrice; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public String getProduct() { return product; } public void setProduct(String product) { this.product = product; } @Override public String toString() { return "Order{" + "orderCode='" + orderCode + '\'' + ", createTime=" + createTime + ", totalPrice=" + totalPrice + ", count=" + count + ", product='" + product + '\'' + '}'; } }
创建订单的main方法
package liojx.kn; import liojx.kn.fnI.CreateFoodOrderImpl; import liojx.kn.fnI.CreateOrder; import liojx.kn.fnI.Order; import java.math.BigDecimal; import java.util.Date; /** * Hello world! * */ public class App { public static void main( String[] args ) { CreateOrder cfo1 = new CreateFoodOrderImpl(); System.out.println(cfo1.createOrder("霸王龙两只")); CreateOrder cfo2 = new CreateOrder() { @Override public Order createOrder(String info) { return new Order("9099XY013", new Date(), new BigDecimal(892.3), 2, info); } }; System.out.println(cfo2.createOrder("三角龙两只")); CreateOrder cfo3 = (String info) -> { return new Order("9099XY014", new Date(), new BigDecimal(32.3), 2, info); }; System.out.println(cfo3.createOrder("甲龙两只")); } }
运行结果
Order{orderCode='9099XY012', createTime=Fri Aug 21 15:48:26 CST 2020, totalPrice=239, count=2, product='霸王龙两只'} Order{orderCode='9099XY013', createTime=Fri Aug 21 15:48:26 CST 2020, totalPrice=892.299999999999954525264911353588104248046875, count=2, product='三角龙两只'} Order{orderCode='9099XY014', createTime=Fri Aug 21 15:48:26 CST 2020, totalPrice=32.2999999999999971578290569595992565155029296875, count=2, product='甲龙两只'}
第一种方式,采用CreateFoodOrderImpl正常实现函数式接口CreateOrder 来创建两只霸王龙的汉堡包。
第二种方式,采用java匿名内部类的方式创建两只三角龙的汉堡包。
第三种方式,采用的是λ表达式来创建两只甲龙的汉堡吧。
其实就是一句话的事:我要一个[传入参数]类型的汉堡包,第一种还创建了实现类,第二种匿名类却简洁了很多,而第三种λ利用语法糖让代码看起来更简洁。
常用函数式接口
Predicate
点开Predicate类,首先看到是@since 1.8 , 接着被@FunctionalInterface标记。同时里面有5个方法,其中方法and、or、negate都是默认方法,isEqual是静态方法,而test
才是它的核心方法。按照咱们之前的理论,一个函数式接口仅有一个抽象方法,即
boolean test(T t);
该方法接收一个参数T,返回一个布尔类型,是一个验证功能的函数。
/** * 创建一个Predicate并实现判断逻辑,判断它是否是苹果 */ Predicate<String> predicate = (String pram) -> { return "apple".equals(pram) ? true : false; }; System.out.println(predicate.test("apple")); // 返回true
and 函数的源码
default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); }
可以看出and 函数表示传入的other对象(T 的子类参数的Predicate对象)需要既满足当前类的test方法,又要满足参数对象类的test方法,返回一个Predicate对象。
代码示例
Predicate<String> pre1 = (String param) -> { return param.length() >= 5; }; Predicate<String> pre2 = (String param) -> { return "L".equals(param.charAt(5) + ""); }; Predicate<String> pre3 = pre1.and(pre2); // and 方法 System.out.println(pre1.test("apple")); // true System.out.println(pre2.test("alibaLba")); //true System.out.println(pre3.test("appleLhb")); // true 满足两个条件:字符数大于等于5,第6个字符为L System.out.println(pre3.test("applehhb")); // false 满足一个条件:字符数大于等于5,第6个字符为h
negate函数:取反
default Predicate<T> negate() { return (t) -> !test(t); }
Predicate<String> pre1 = (String param) -> { return param.length() >= 5; }; Predicate<String> pre4 = pre1.negate(); System.out.println(pre4.test("aaaa")); // true System.out.println(pre4.test("aaaaa")); // false
同理,or函数,取并集,isEqual判断是否相等。
Consumer
它的函数式接收一个T对象,函数处理后,不返回任何结果。
void accept(T t);
譬如, 传入一个Order对象,打印它每个字段的值。
Consumer<Order> con = (Order order) -> { System.out.println(order.toString()); }; con.accept(new Order("9099XY015", new Date(), new BigDecimal(32.3), 2, "风神翼龙")); // 输出结果
// Order{orderCode='9099XY015', createTime=Fri Aug 21 17:05:51 CST 2020, totalPrice=32.2999999999999971578290569595992565155029296875, count=2, product='风神翼龙'}
它还提供一个默认的方法andThen, 意为先处理,紧接着又处理。
Consumer<Order> con = (Order order) -> { System.out.println(order.toString()); }; con.accept(new Order("9099XY015", new Date(), new BigDecimal(32.3), 2, "风神翼龙")); Consumer<Order> con2 = (Order o) -> { System.out.println(o.getTotalPrice().add(new BigDecimal(200))); }; con = con.andThen(con2); // andThen 的前面对象方法先执行,参数对象的方法后执行 con.accept(new Order("9099XY015", new Date(), new BigDecimal(32.3), 2, "风神翼龙"));
// 结果
// Order{orderCode='9099XY015', createTime=Fri Aug 21 17:12:48 CST 2020, totalPrice=32.2999999999999971578290569595992565155029296875, count=2, product='风神翼龙'}
// Order{orderCode='9099XY015', createTime=Fri Aug 21 17:12:48 CST 2020, totalPrice=32.2999999999999971578290569595992565155029296875, count=2, product='风神翼龙'}
// 232.2999999999999971578290569595992565155029296875
Function<T, R>
/** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t);
它接收一个T对象,计算后返回一个R对象。
Function<String, Integer> fun = (String t) -> { String [] arr = t.split(""); return Integer.parseInt(arr[1]) + 200; }; System.out.println(fun.apply("23123")); // 203
默认方法 compose 和 andThen,区别在于前者是传入的参数先执行,后者是传入的参数后执行,看示例
Function<String, Integer> fun = (String t) -> { String [] arr = t.split(""); return Integer.parseInt(arr[1]) + 200; }; Function<Integer, String> fun2 = (Integer t) -> { return String.valueOf(t); }; Function fun3 = fun.compose(fun2); System.out.println(fun3.apply(8999993)); // 209 先执行fun2 再执行fun System.out.println(fun3.apply(8999993) instanceof Integer); // true Function fun4 = fun.andThen(fun2); // System.out.println(fun4.apply(8999993)); // 先执行fun 在执行fun2 // 报错 Exception in thread "main" // java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String // 由于fun执行完了返回的是String对象,紧接着把fun返回的对象作为fun2的参数对象,fun2参数需要Integer,故报类型错误 System.out.println(fun4.apply("8999993")); // 209 先执行fun 在执行fun2 System.out.println(fun4.apply("8999993") instanceof Integer); // false
可以看出,他们区别即是先后顺序。
identity() 是一个无参数的静态方法,传入什么返回什么
// identity 传进来什么就返回什么,类似于 t-> t,实际代码也是这样 Stream<String> stream = Stream.of("a","bb","ccc","dddd","eeeee","ffffff"); Stream<String> stream1 = Stream.of("a","bb","ccc","dddd","eeeee","ffffff"); Map<String, Integer> collect = stream.collect(Collectors.toMap(Function.identity(), String::length)); Map<String, Integer> collect2 = stream1.collect(Collectors.toMap(t -> t, String::length)); System.out.println(collect); // {bb=2, a=1, ccc=3, ffffff=6, eeeee=5, dddd=4} System.out.println(collect2); // {bb=2, a=1, ccc=3, ffffff=6, eeeee=5, dddd=4}
Supplier<T>
supplier提供了一个get方法,返回一个泛型的T对像。
Supplier<String> sup = () -> { Stream<String> st = Stream.of("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p", "q","r","s","t","u","v","w","x","y","z"); Random r = new Random(); double v = 0; List<String> list = st.collect(Collectors.toList()); StringBuffer sb = new StringBuffer(); int len = 10, word = 3; for (int i = 0; i < word; i++){ for (int j = 0 ;j < len; j++ ){ int a = -1; while(a > 25 || a < 0) { v = r.nextDouble(); a = (int)(v*100); } sb.append(list.get(a)); } sb.append(" "); } return sb.toString(); }; System.out.println(sup.get());
UnaryOperator<T>
unaryOperator本身没有抽象方法,它继承自Function<T, T>,区别在于function是接收一个参数T,返回一个对象R。而unaryOperator是接受一个参数T,返回一个T对象。
UnaryOperator<Integer> unaryOperator = (Integer i) -> { return i + 23; // 这里返回int,返回其它类型就报错 }; System.out.println(unaryOperator.apply(30)); // 53
BinaryOperator<T>
binaryOperator继承自BiFunction<T,T,T>,BiFunction的方法是
/** * Applies this function to the given arguments. * * @param t the first function argument * @param u the second function argument * @return the function result */ R apply(T t, U u);
接收一个参数T和一个参数U,返回一个R。
例如:
BinaryOperator<Integer> binaryOperator = (Integer i1, Integer i2) -> { return i1 > i2 ? i1 : i2; }; System.out.println(binaryOperator.apply(50,70)); // 70
总结:上面都是常用的函数式接口,而java.util.function提供了大量的函数式接口。用以应对不同的应用场景。