Java8新特性(四):函数式接口(Function,Predicate,Supplier,Consumer)

781 阅读4分钟

函数式接口(Function,Predicate,Supplier,Consumer)

Function

  • 常用的方法 R apply(T t)

将Function对象应用到输入的参数上,然后返回计算结果。

测试例子

      public class TestFunction {
      /**
       * Function<T t,R r>函数式接口
       * R apply(T t);    数据类型转换
       *
       * @param s
       * @param function
       */
      public static void change(String s, Function<String, Integer> function) {
          //字符串类型的整数 转换为Integer类型的整数
          int in = function.apply(s);
          System.out.println(in);
      }

      /**
       * andThen(Function<T t,R r>);
       *
       * @param s
       * @param fun1
       * @param fun2
       */
      public static void change02(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {
          String ss = fun1.andThen(fun2).apply(s);
          System.out.println(ss);
      }

      public static int change03(String s, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
          return fun1.andThen(fun2).andThen(fun3).apply(s);
      }

      public static void main(String[] args) {
          String s = "12345";
          String ss = "小小明,20";
          change(s, str -> Integer.parseInt(s));
          change02(s, str -> Integer.parseInt(s) + 10, i -> i + "");
          int num = change03(ss, str -> str.split(",")[1], str -> Integer.parseInt(str), i -> i + 100);
          System.out.println("num: " + num);
      }
       }

结果

12345
12355
num: 120

Predicate

有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用java.util.function.Predicate 接口。

  • 常用的方法

    boolean test(T t);

Predicate 接口中包含一个抽象方法,返回一个boolean值进行判断。

测试例子

public class TestPredicate {

  /**
   * boolean test(T t);  获取布尔类型结果
   *
   * @param s
   * @param pre
   * @return
   */
  public static boolean checkString(String s, Predicate<String> pre) {
      return pre.test(s);
  }

  /**
   * and();   代表&&的意思
   * <p>
   * 传递两个Predicate接口,比如:
   * 一个用于判断字符串的长度是否大于5
   * 一个用于判断字符串中是否包含a
   * 两个条件必须同时满足
   *
   * @param s
   * @param pre
   * @return
   */
  public static boolean checkStringAnd(String s, Predicate<String> pre1, Predicate<String> pre2) {
      return pre1.and(pre2).test(s);
  }

  /**
   * or();   代表||的意思
   *
   * @param s
   * @param pre1
   * @param pre2
   * @return
   */
  public static boolean checkStringOr(String s, Predicate<String> pre1, Predicate<String> pre2) {
      return pre1.or(pre2).test(s);
  }

  /**
   * negate取反
   *
   * @param s
   * @param pre
   * @return
   */
  public static boolean checkStringNegate(String s, Predicate<String> pre) {
      return pre.negate().test(s);
  }

  /**
   * 方法的参数传递一个包含人员信息的数组
   * 传递两个Predicate接口,用于对数组中信息进行过滤
   * 把满足条件的信息存到ArrayList集合中并返回
   *
   * @return
   */
  public static ArrayList<String> filter(String arr[], Predicate<String> pre1, Predicate<String> pre2) {
      ArrayList<String> list = new ArrayList<>();
      for (String s : arr) {
          boolean b = pre1.and(pre2).test(s);
          if (b) {
              list.add(s);
          }
      }
      return list;
  }

  public static void main(String[] args) {

      String s = "abcdef";
      //长度大于5
      boolean b = checkString(s, str -> str.length() > 5);
      System.out.println(b);

      //长度大于6并且包含"a"
      boolean and = checkStringAnd(s, str -> str.length() > 6, str -> str.contains("a"));
      System.out.println(and);

      //长度大于6 或者 包含"a"
      boolean or = checkStringOr(s, str -> str.length() > 6, str -> str.contains("a"));
      System.out.println(or);

      //取反
      boolean negate = checkStringNegate(s, str -> str.length() > 5);
      System.out.println(negate);

      //过滤操作
      String arr[] = {"张小三,男", "小红,女", "李四,男", "小小明,男"};
      ArrayList<String> list = filter(arr, str -> "男".equals(str.split(",")[1])
              , str -> str.split(",")[0].length() > 2);
      list.forEach(System.out::println);
  }
  }

结果

true
false
true
false
张小三,男
小小明,男

Supplier

泛型传递什么类型数据,get方法就返回什么类型数据。所以Supplier被称之为生产型接口

  • 常用的方法

    T get();

该接口中只包含这一个抽象方法。

测试例子

   public class TestSupplier {
          public static void main(String[] args) {

              String s = getString(() -> {
                  return "hello world";
              });
              System.out.println(s);

              //优化lambda
              String s2 = getString(() -> "hello java");
              System.out.println(s2);

              int[] arr = {34, 45, 23, 1, 345, -54};
              int maxVal = getMax(() -> {
                  int max = arr[0];
                  for (int i : arr) {
                      if (i > max) {
                          max = i;
                      }
                  }
                  return max;
              });
              System.out.println(maxVal);
          }

          /**
           * 会返回一个String
           *
           * @param sup
           * @return
           */
          public static String getString(Supplier<String> sup) {
              return sup.get();
          }

          /**
           * 返回一个最大值
           *
           * @param sup
           * @return
           */
          public static int getMax(Supplier<Integer> sup) {
              return sup.get();
          }
      }
      

结果

hello world
hello java
345

Consumer

java.util.function.Consumer 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据, 其数据类型由泛型决定。

  • 常用的方法

    void accept(T t);

Consumer 接口中包含抽象方法 void accept(T t) ,意为消费一个指定泛型的数据。

测试例子

  public class TestConsumer {
    public static void method(String name, Consumer<String> consumer) {
        consumer.accept(name);
    }

    public static void method02(String name, Consumer<String> con1, Consumer<String> con2) {
        //使用andThen方法,先把两个Consumer接口连接在一起,在消费数据
        //con1连接con2,先执行con1消费数据,在执行con2消费数据
        con1.andThen(con2).accept(name);
    }

    public static void printInfo(String[] arr, Consumer<String> con1, Consumer<String> con2) {
        for (String message : arr) {
            con1.andThen(con2).accept(message);
        }
    }

    public static void main(String[] args) {
        method("neoooo", (name) -> {
            //对传递的字符串进行消费
            //消费方式:直接输出字符串
            //System.out.println(name);

            //消费方式:把字符串进行反转输出
            String reverse = new StringBuffer(name).reverse().toString();
            System.out.println(reverse);
        });
        //调用method02方法,传递一个字符串,两个lambda表达式
        method02("nizhenniubi", (name) -> {
            System.out.println(name.toUpperCase());
        }, (name) -> {
            System.out.println(name.toLowerCase());
        });

        String arr[] = {"zhangsan,male", "lisi,male", "wanger,female"};
        printInfo(arr, (message) -> {
            String name = message.split(",")[0];
            System.out.println("姓名:" + name);
        }, (message) -> {
            String sex = message.split(",")[1];
            System.out.println("性别:" + sex + " ");
        });
    }
}

结果

ooooen
NIZHENNIUBI
nizhenniubi
姓名:zhangsan
性别:male 
姓名:lisi
性别:male 
姓名:wanger
性别:female 

混合使用

例子

public class TestAll {
    static List<Emp> emps = Arrays.asList(
            new Emp(1, "yw"),
            new Emp(2, "yt"),
            new Emp(3, "yp"),
            new Emp(4, "yc"));

    private static <T,R> void printEmpNameWhenEmpNoLg1(Iterable<T> source, Predicate<T> predicate, Function<T,R> function,
                                                Consumer<R> consumer)
    {
        for(T t:source)
        {
            if(predicate.test(t))
            {
                R r = function.apply(t);
                consumer.accept(r);
            }
        }
    }

    public static void main(String[] args) {
        Predicate<Emp> predicate = emp -> emp.getEmpno()>2;
        //定义函数
        Function<Emp,String> function = emp -> emp.getEname();
        //定义消费者
        Consumer<String> consumer = System.out::println;
        TestAll.printEmpNameWhenEmpNoLg1(emps,predicate,function,consumer);
    }
}


    public class Emp {
        private int empno;
        private String ename;

        public Emp(int empno, String ename) {
            this.empno = empno;
            this.ename = ename;
        }

        public int getEmpno() {
            return empno;
        }

        public void setEmpno(int empno) {
            this.empno = empno;
        }

        public String getEname() {
            return ename;
        }

        public void setEname(String ename) {
            this.ename = ename;
        }

        public static void printEmp(Emp emp){
            System.out.println("empno:"+emp.getEmpno()+"\nename:"+emp.getEname());
        }


    }

结果

yp
yc

源码下载

本文章例子源码

Java8新特性系列