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提供了大量的函数式接口。用以应对不同的应用场景。

目录

  飞回

posted @ 2020-08-21 18:03  正宗老菜鸟  阅读(952)  评论(0编辑  收藏  举报