Java foundation - Functional Programming Interface papers

1. Function Interface

1.1 Functional Interface Introduction

Function in Java interface means: one and only one method of abstract interfaces .

Function interface, an interface that is suitable for functional programming scenarios. The functional programming in Java is reflected Lambda, so the function interface is that you can apply to interfaces Lambda use. Only by ensuring the interface and only one abstract method, Java can be deduced in the Lambda smoothly.

From the application level is concerned, Java in the Lambda can be treated as a "syntactic sugar" anonymous inner class, but the two are different in principle.

1.2 Format

Just make sure there is one and only one interface to abstract method:

修饰符 interface 接口名称 {
    public abstract 返回值类型 方法名称(可选参数信息);
    // 其他非抽象方法内容
}

1.3 @FunctionalInterface comment

And the role of @Override similar annotations, Java 8 in specially introduced a new annotated functional interfaces: @FunctionalInterface. The annotation can be used for defining an interface:

@FunctionalInterface
public interface MyFunctionalInterface {
    void myMethod();
}

By using this annotation to define interfaces, the compiler will be forced to check whether the interface does have one and only one abstract method, otherwise it will error. Note that, even without the use of notes, as long as the definition of functional interface, which is still a function interface, use all the same.

Custom Function Interface 1.4

For just defined MyFunctionalInterface function interface, a typical scenario is used as a parameter of the method:

  public  static  void show(MyFunctionalInterface func){
    func.mythond();
  }
  public static void main(String[] args) {
    // 传入匿名内部类
    show(new MyFunctionalInterface() {
      @Override
      public void mythond() {
        System.out.println("执行了");
      }
    });
    // 简写Lambda表达式
    show(()-> System.out.println("执行了"));
  }

2. Functional Programming

On the basis of taking into account the characteristics of the object-oriented, Java language cited by Lambda expressions and methods, functional programming opens the door for developers. Let's do a Preliminary Study.

2.1 Lambda delay execution

After some scenes of the code execution, the result will not necessarily be used, resulting in a waste of performance. The Lambda expressions are delayed execution, which can just as solutions to enhance performance.

Performance Logs waste case

Note: The log can help us quickly locate problems, document case the program is running in order to monitor and optimize the project. A typical scenario is that the parameters of conditions, for example after splicing log messages, in the printout condition is satisfied:

public class Demo01Logger {
    private static void log(int level, String msg) {
        if (level == 1) {
            System.out.println(msg);
        }
    }
    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";
        log(1, msgA + msgB + msgC);
    }
}

Problems code: meets the requirements regardless of the level, as the second parameter log method, three strings will be spliced ​​and passing the first method, then the level will be determined. If the level is not met, then the splicing operation strings for nothing, there is a performance wasted.

Note : SLF4J is widely used logging framework, its performance in order to solve this problem of waste, is not recommended for splicing first string in the log, but the number of the string variable as a parameter passed to the method , only the string will be spliced in the case of the log level to meet the requirements. For example: LOGGER.debug ( ". The value of variable {} {}", "os", "macOS"), wherein the braces {} placeholder. If the log level to meet the requirements, it will be "os" and "macOS" two strings in turn spliced to position braces; otherwise they would not perform string concatenation. This is also a viable solution, but Lambda can do better.

Experience better wording of Lambda

Lambda necessarily need to use a function interface:

@FunctionalInterface
public interface MessageBuilder {
  String message();
}

Then log transformation method

public class Test01 {
  private static  void  log(int level,MessageBuilder builder){
    if(level==1){
      String mes = builder.message();
      System.out.println(mes);
    }
  }
  public static void main(String[] args) {
    String msgA = "Hello";
    String msgB = "World";
    String msgC = "Java";
    log(1,()-> msgA+msgB  +msgC);
  }
}

As a result, only when the level to meet the requirements, will be spliced ​​with three strings; otherwise the three strings will not be spliced

2.2 using a Lambda value as a parameter and return

If you put aside to achieve the principle does not say, Java in Lambda expressions may be used as a substitute for anonymous inner classes.

If the parameter is a function of process interface type, Lambda expressions can be used instead.

Lambda expressions use as a method parameter, in fact, use the function interface as a parameter. E.g. java.lang.Runnable interface is a function interface, assume that a startThread method using the interface as an argument, it can be used for parameter passing Lambda. In fact, this case and the Thread class constructor parameters Runnable no essential difference.

  public static void startThead(Runnable run){
    new Thread(run).start();
  }
  public static void main(String[] args) {
    startThead(()-> System.out.println(Thread.currentThread().getName()));
  }

Similarly, if the return value of a function of process type is an interface, it can be returned directly to a Lambda expression. A need to get the object java.util.Comparator interface type by a method as a sequencer, can be adjusted when the acquisition method.

  private static Comparator<String> newComparator() {
      return (o1, o2) -> o1.length()-o2.length();
  }
  public static void main(String[] args) {
    // 对字符串数组排序,按照字符长度排序
    String[]arr = {"ab","b","abc","abcde","abcd","aaaaaa"};
    //
    Arrays.sort(arr);
    Arrays.sort(arr,newComparator());
    System.out.println(Arrays.toString(arr)); // [b, ab, abc, abcd, abcde, aaaaaa]
  }

Lambda expressions which can be a direct return.

3. The common function interface

JDK provides a number of interface functions common to enrich Lambda typical usage scenario, which is provided mainly in the java.util.function package. The following is a simple example of the use of several interfaces.

3.1 Supplier Interface

java.util.function.Supplier interface contains only a non-reference method: T get (). Used to obtain a generic parameter specifies the type of object data. Since this is a function interface, which means that the corresponding Lambda expressions need to "provide external" in line with a generic type of object data

  public static String show(Supplier<String> sp){
    return sp.get();
  };
  public static void main(String[] args) {
    System.out.println(show(()->"你好Java"));
  }

Exercise: Find the maximum array

  public static int getMax(Supplier<Integer> sp){
    return sp.get();
  }
  public static void main(String[] args) {
    int[]arr={11,2,3,6,4,66,22,19};
    int max = getMax(()->{
      int maxValue = arr[0];
      for (int i = 1; i < arr.length; i++) {
        if(maxValue<arr[i]){
          maxValue = arr[i];
        }
      }
      return maxValue;
    });
    System.out.println(max);
  }

3.2 Consumer Interface

java.util.function.Consumer the interface is just the opposite with the Supplier Interface, it is not a data production, but consumption data, the data type of the generic decision.

  • Abstract methods : accept, Consumer interfaces include an abstract method void accept (T t), are intended consumption data is designated as a generic. The basic use such as:

      public static void printList(ArrayList<String> list, Consumer<ArrayList> con){
        con.accept(list);
      }
      public static void main(String[] args) {
          ArrayList<String> list = new ArrayList<>();
          list.add("张三");
          list.add("李四");
          list.add("王五");
          printList(list,arrayList->{
            for (int i = 0; i < arrayList.size();i++){
              System.out.println("姓名:" + arrayList.get(i));
            }
          });
      }
  • The default method : If a method parameters and return values are all Consumer types, then you can achieve the effect: consumption data, the first thing to do an operation, and then make an operation, to achieve combination. This method is the default method and Consumer interface andThen. Below is the source code JDK:

    • Source

      default Consumer<T> andThen(Consumer<? super T> after) {
          Objects.requireNonNull(after);
          return (T t) ‐> { accept(t); after.accept(t); };
      }
      /*
      备注: java.util.Objects 的 requireNonNull 静态方法将会在参数为null时主动抛出
      NullPointerException 异常。这省去了重复编写if语句和抛出空指针异常的麻烦。
      */
    • Code

      //要想实现组合,需要两个或多个Lambda表达式即可,而 andThen 的语义正是“一步接一步”操作。例如两个步骤组合的情况:
        public static void printList(ArrayList<String> list, Consumer<ArrayList> one,Consumer<ArrayList> two){
          one.andThen(two).accept(list);
        }
        public static void main(String[] args) {
          ArrayList<String> list = new ArrayList<>();
          list.add("张三");
          list.add("李四");
          list.add("王五");
          printList(list,arrayList->{
            System.out.println("======顺序打印=======");
            for (int i = 0; i < arrayList.size();i++){
              System.out.println("姓名:" + arrayList.get(i));
            }
          },arrayList -> {
            System.out.println("======倒序打印=======");
            for (int i = arrayList.size()-1; i >=0;i--){
              System.out.println("姓名:" + arrayList.get(i));
            }
          });
        }

3.3 Predicate Interface

Sometimes we need to be determined for certain types of data, to thereby obtain a boolean result. Then you can use java.util.function.Predicate interface.

Abstract test method

Predicate interfaces include an abstract method: boolean test (T t). Conditions for determining a scene:

  public static void main(String[] args) {
    // 判断一个字符串中是否包含大写的J和大写的H
    String str = "Hello Java";
    boolean isHas = checkStr(str,data->data.contains("J")&&data.contains("H"));
    System.out.println(str + "是否包含大写J和H:"+isHas);
  }
  public static boolean checkStr(String str , Predicate<String> predicate){
    return predicate.test(str);
  }

The default method and, or, nagate

  • method
// and 且
default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) ‐> test(t) && other.test(t);
}
// or 或
default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) ‐> test(t) || other.test(t);
}
// nagate非
default Predicate<T> negate() {
  return (t) ‐> !test(t);
}
  • Code

    // and
      public static void main(String[] args) {
        // 判断一个字符串中是否包含大写的J和大写的H
        String str = "Hello Java";
        boolean isHas = checkStr(str,data->data.contains("J"),data->data.contains("H"));
        System.out.println(str + "包含大写J和H:"+isHas);
      }
      public static boolean checkStr(String str , Predicate<String> one,Predicate<String> two){
        return one.and(two).test(str);
      }
    // or
      public static void main(String[] args) {
        // 判断一个字符串中是否包含大写的J和大写的H
        String str = "Hello Java";
        boolean isHas = checkStr(str,data->data.contains("J"),data->data.contains("H"));
        System.out.println(str + "包含大写J或H:"+isHas);
      }
      public static boolean checkStr(String str , Predicate<String> one,Predicate<String> two){
        return one.or(two).test(str);
      }
    }
    // nagate
      public static void main(String[] args) {
        // 判断一个字符串中是否包含大写的J和大写的H
        String str = "Hello Java";
        boolean isHas = checkStr(str,data->data.contains("J")&&data.contains("H"));
        System.out.println(str + "没有包含大写J和H:"+isHas);
      }
      public static boolean checkStr(String str , Predicate<String> predicate){
        return predicate.negate().test(str);
      }
    }

3.4 Function Interface

java.util.function.Function<T,R> Another type of interface is used to obtain data in accordance with a type of data, the former is called pre-conditions, which is referred to as post-conditions.

Abstract method: apply

Function main interface is an abstract method: R apply (T t), the result acquired according to the type of the parameter R type T. Use scenario for example: to convert the type Integer String type.

  public static void main(String[] args) {
    methond(str->{
      return Integer.parseInt(str);
    });
    // 打印结果30
  }
  public static void methond(Function<String,Integer> func){
    Integer num = func.apply("20");
    System.out.println(num + 10);
  }

The default method: andThen

Function interface andThen a default method used for combining operation. JDK source code such as:

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) ‐> after.apply(apply(t));
}

The scenario method is also used for "what to do first, what to do," the Consumer and the andThen similar:

  public static void main(String[] args) {
    // 将一个字符串变成数字后,再乘以10的结果
    test(str->Integer.parseInt(str),num->num * 10);
  }
  public static void test(Function<String,Integer> one,Function<Integer,Integer> two){
    int result = one.andThen(two).apply("20");
    System.out.println("结果是:" + result);

  }

Guess you like

Origin www.cnblogs.com/bruce1993/p/11888423.html