Java8函数接口

Java8你真的懂吗? 专栏收录该内容
1 篇文章 0 订阅

Java函数接口

函数接口概述

什么是函数接口:函数接口就是只定义一个抽象方法的接口,但同时可以拥有默认方法,为了简化函数方法的实现可以使用lambda表达式,其基本语法如下:

(parameters) -> expression # 控制流语句需要使用{}

Java函数编程:原始类型转换成对应的引用类型,Java中的泛型只能绑定引用类型,这由泛型内部的实现方式造成的,Java中包括一个将原始基本类型转换成引用类型的机制,成为装箱,反过程为拆箱操作。IntPredicate等可以避免自动装箱操作,对于专门的输入参数类型的函数式接口,如DoublePredicate,IntConsumer,Function输出参数的变种为ToIntFunction和IntToDoubleFunction

如下图的常见函数接口的表格(多看看函数接口源码熟练使用即可):

Function接口

1、Function 接口的作用

     代表一个方法,可以接收一个参数,并产生一个结果,泛型参数T代表输入参数类型,R代表产生出参J数类型

2、Function 接口的实现

   (因为函数编程参数即是动作,接下来介绍的时候对Function称之为操作)。函数接口由@FcuntionalInterface注解修饰,并且只能有一个接口参数,但可以同时包括多个default函数。如下Function接口的源码:

@FunctionalInterfacepublic interface Function<T, R> {    //  该函数标识对参数T使用Function进行处理,产生R类型的结果    R apply(T t);      // 例如 A.compose(B).apply(v);先对v使用B操作,再进行A操作。A为调用者    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {        Objects.requireNonNull(before);        return (V v) -> apply(before.apply(v));    }    // 例如 A.andThen(B).apply(v);对v先进行A操作,再进行B操作    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {        Objects.requireNonNull(after);        return (T t) -> after.apply(apply(t));    }    // 返回一个总是返回它的输入参数的Function,此时结果和输入参数均为T    static <T> Function<T, T> identity() {        return t -> t;    }}

3、应用

1、Function使用案例(基于Java8的网络爬虫):

    当使用Java中国的OkHttp网络框架和Jsoup框架处理网络爬虫的时候,常常会根据不同的平台对不同页面进行处理,所以为了规范化以及行为参数化处理,我这里以此为背景,写了一个Function类型的HTTP超文本标签id为某某某的属性解析器。

  // Function函数结构规范  private static String parserHtmlBy(Document document, Function<Document, String> idFunction) {      if (Objects.isNull(idFunction) || Objects.isNull(document)) {          return "";      }      // 此处使用了apply函数      return idFunction.apply(document);    }  public static void main(String[] args) throws IOException {      OkHttpClient client = new OkHttpClient();      String uri = "https://www.bilibili.com/";      Response httpBody = client.newCall(new Request.Builder().url(uri)              .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36")              .build()).execute();      if (!httpBody.isSuccessful()) {          throw new HttpRetryException("Http Request Exception", httpBody.code());      }      Document html = Jsoup.parse(httpBody.body().string());      // 不同的页面可能使用Function不一致,所以这里使用Function对函数进行封装      // 行为参数化,行为idFunction对html参数进行处理      String headWrapper = parserHtmlBy(html, document -> {          Element idToValue = html.getElementById("reportFirst1");          Map<String, String> attrs = Maps.newHashMap();          Optional.ofNullable(idToValue).ifPresent(t -> {              idToValue.attributes().forEach(attribute -> {                  attrs.put(attribute.getKey(), attribute.getValue());              });          });          return new GsonBuilder().create().toJson(attrs);      });      System.out.println("哔哩哔哩 " + headWrapper);  }

2、关于compose,andThen,identity函数的研究(请看一下源码中的Doc分析)

Function<Integer,Integer> multi = i->i*i;Function<Integer,Integer> resize = i->i*2;// 执行顺序,resize,multi。结果为16System.out.println(multi.compose(resize).apply(2));// 执行顺序,multi,resize。结果为8System.out.println(multi.andThen(resize).apply(2));// 直接输出原值。结果为2System.out.println(Function.identity().apply(2));

Predicate接口

1、predicate函数结构作用

      代表一个方法,可以接收一个参数,并根据某一规则判断,该参数是否符合该规则,根据规则过滤数据信息。

2、predicate函数接口实现

  (因为函数编程参数即是动作,接下来介绍的时候对Predicate称之为操作)。函数接口由@FunctionalInterface注解修饰,并且只能有一个接口参数,但可以同时包括多个default函数。如下Predicate接口的源码:

@FunctionalInterfacepublicinterface Predicate<T> {    // 判断传入的参数是否符合某种规则    boolean test(T t);    // 判断传入的参数是否符合某些规则    default Predicate<T> and(Predicate<? super T> other) {        Objects.requireNonNull(other);        return (t) -> test(t) && other.test(t);    }    // 判断传入的参数是否不符合某种规则    default Predicate<T> negate() {        return (t) -> !test(t);    }    // 判断传入的参数是否符合多种规则中的某一种    default Predicate<T> or(Predicate<? super T> other) {        Objects.requireNonNull(other);        return (t) -> test(t) || other.test(t);    }    // 判断两个对象是否相等,Predicate接口的静态方法    static <T> Predicate<T> isEqual(Object targetRef) {        return (null == targetRef)? Objects::isNull : object -> targetRef.equals(object);    }}

3、predicate函数接口使用(选茶叶)

public class TeaFilter {    @Data    @ToString    @AllArgsConstructor    static class Tea {        String type;        String price;    }    private static List<Tea> filter(List<Tea> teas, Predicate<Tea> t) {        List<Tea> suit = Lists.newLinkedList();        for (Tea tea : teas) {            // negate            if (t.test(tea)) {                suit.add(tea);            }        }        return suit;    }    public static void main(String[] args) {        List<Tea> teas = Arrays.asList(new Tea("龙绿茶", "100"),                new Tea("龙井", "1000"),                new Tea("信阳毛尖", "10000")        );        // test操作        List<Tea> tea = filter(teas, x -> x.getType().endsWith("毛尖"));        // or 操作        Predicate<Tea> teaOrPredicate = x -> x.getType().startsWith("龙");        Predicate<Tea> teaOrPredicateOther = x -> x.getPrice().compareTo("10") >= 0;        filter(teas, teaOrPredicate.or(teaOrPredicateOther)).forEach(x -> System.out.println(x.toString()));        System.out.println("==========");        // and 操作        Predicate<Tea> teaAndPredicate = x -> x.getType().startsWith("龙");        Predicate<Tea> teaAndPredicateOther = x -> x.getPrice().compareTo("1000") >= 0;        filter(teas, teaAndPredicate.and(teaAndPredicateOther)).forEach(x -> System.out.println(x.toString()));        // 比较对象isEqual,可用于对象比较,但是不建议        Predicate<Tea> isEqual = Predicate.isEqual(new Tea("普洱", "100"));        System.out.println(isEqual.test(new Tea("普洱", "1000")));    }}

Suppiler接口

1、Suppiler函数接口作用 

    Suppiler函数接口的作用,根据提供者返回结果,函数签名为 ()->T

2、Suppiler函数接口源码

// 返回一个提供者的结果@FunctionalInterfacepublic interface Supplier<T> {    // 返回一个结果    T get();}

3、举例子(一个对象的某个字段的值的获取和默认值):

publicstatic String suppiler(Supplier<String> suppiler, String defaultValue) {    String val = suppiler.get();    if (val == null || "".equals(val)) {        return defaultValue;    }    return val;}private static String sval(Supplier<String> suppiler) {    return suppiler(suppiler, "NA");}// 可以是任意一个引用类型,此时返回一个值public static void main(String[] args) {    System.out.println(sval(new Node("")::getName));}

​​​​​​​Consumer接口

1、Consumer接口作用

   java.util.function.Consumer<T>定义了一个名叫accept的抽象方法,它接受泛型T的对象,没有返回(void),可以简单的理解为消费者。

2、Consumer函数接口实现

// 与其他函数接口不同的是,Consumer接口操作产生副作用// T 代表输入参数类型@FunctionalInterfacepublic interface Consumer<T> {    //  对给定参数执行操作,没有返回值    void accept(T t);    // 返回组成的{@code Consumer},依次执行此操作    // 操作,然后进行{@code after}操作。如果执行任何一个操作会引发异常,它将被中继给    // 组合操作。如果执行此操作会引发异常,{@code after}操作将不会执行。    default Consumer<T> andThen(Consumer<? super T> after) {        Objects.requireNonNull(after);        return (T t) -> {            accept(t);            after.accept(t);        };    }}

3、Consumer函数接口使用

public static void consumer(List<String> list, Consumer<String> consumer){    for(String s : list){        consumer.andThen(consumer).accept(s);    }}public static void main(String[] args) {    List<String> costMoney = new ArrayList<>();    costMoney.add("dollars"); // 美元    costMoney.add("yen");     // 日元    costMoney.add("RMB");     // 人民币    consumer(costMoney, System.out::println);}

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值