Java function interface

Java function interface

1. Function Interface

1.1 concept

  • Functional Interface: There is only one interface of the abstract method, function call interface.
  • Of course, the interface can also contain other methods (static, default, private)
  • @FunctionalInterface comment
    • Action: the interface can detect whether the interface is a function
      • Is: Compile success
      • No: Compilation failed (no abstract interface method, or excess number of abstract methods 1)

Note: " syntactic sugar " refers to the use of more convenient, but the principle is the same code syntax. For example, for-each syntax to use when traversing a collection, in fact, achieve the underlying principle remains the iterator, which is " syntactic sugar ." From the application level is concerned, Java in the Lambda could be seen as "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 static abstract 返回值类型 函数名称(参数列表);
    
    // 其他非抽象方法内容
    }

1.3 Use functional interface

@FunctionalInterface
public interface MyFunctionalInterface {
    public abstract void method();

}

// ===============
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface {
    @Override
    public void method() {
        System.out.println("使用实现类重写接口中的抽象方法");

    }
}

// ============

/*
    函数式接口的使用:一般可以作为方法的参数和返回值类型
 */
public class Demo01MyFunctionalInterface {
    public static void main(String[] args) {
        // 调用show方法,方法的参数是一个函数式接口,所以可以传递接口的实现类对象
        show(new MyFunctionalInterfaceImpl());
        // 调用show方法,方法的参数是一个函数式接口,所以可以传递接口的匿名内部类
        show(new MyFunctionalInterface() {
            @Override
            public void method() {
                System.out.println("使用匿名内部类重写接口中的抽象方法");
            }
        });

        // 使用lambda表达式
        show(() -> {
            System.out.println("使用lambda表达式重写接口中的抽象方法");
        });
        // 简化lambda表达式
        show(() -> System.out.println("简化之后"));

    }

    /*
    定义一个方法,方法的参数是一个函数式接口MyFunctionalInterface
     */
    public static void show(MyFunctionalInterface myinter) {
        myinter.method();
    }
}

2. Functional Programming

2.1 Lambda delay the implementation of

Performance Logs waste case

Note: The log can help us quickly locate the problem, the situation recorded program is running in order to monitor and optimize the project.

/*
    日志案例
    问题:
        发现以下代码存在一些性能浪费的问题
        调用showLog方法,方法的第二个参数是一个拼接的字符串
        先把字符串拼接好,然后调用showLog方法
        showLog方法中如果传递的日志等级不是1级
        那么就会觉得拼接好的字符串没有使用,存在了浪费
 */
public class Demo01Logger {
    /*
        定义一个根据日志级别,显示日志信息的方法
     */
    public static void showLog(int level, String message) {
        // 对日志级别进行判断,如果是1级别,那么输出信息
        if (1 == level) {
            System.out.println(message);
        }
    }
    public static void main(String[] args) {
        // 定义三个日志信息
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";

        showLog(2, msgA+msgB+msgC);

    }
}

Lambda expressions using optimization

public interface Message {
    // 定义一个返回拼接字符串的抽象方法
    public abstract String builderMessage();
}

// =========
/*
    使用Lambda表达式优化日志案例
    Lambda的特点:延迟加载
    Lambda的使用前提:必须存在函数式接口

    使用Lambda表达式作为参数传递,仅仅是把参数传递到showLog方法中
    只有满足条件,日志的等级是1级
        才会调用接口Message中的builderMessage方法
        才会进行字符串的拼接
    如果不满足条件,日志的等级不是一级
    那么Message接口中的方法builderMessage不会执行
    所以拼接字符串的代码也不会执行,不会存在性能的浪费

 */
public class Demo02Logger {

    public static void main(String[] args) {
        // 定义三个日志信息
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";
        // 调用showLog方法,参数msg是一个函数式接口,所以可传递Lambda表达式
        showLog(2, () -> {
            System.out.println("不满足条件不执行");
            return msgA+msgB+msgC;
        });

    }
    /*
        定义一个方法,用来显示日志信息
        日志等级和函数式接口Message作为方法的参数
     */
    public static void showLog(int level, Message msg) {
        if (level == 1) {
            System.out.println(msg.builderMessage());
        }
    }
}

As a method of using a Lambda 2.2 & parameter return value

E.g. java.lang.Runnable interface is a function interface. Suppose there is a method using the same interface as the startThrea method parameters, it can be used for parameter passing Lambda. In fact, this case and the Thread class constructor parameter is no essential difference Runnable

public class Demo01Runnable {
    // 定义一个方法startThread,方法的参数使用函数式接口Runnable
    public static void startThrea(Runnable run) {
        // 开启多线程
        new Thread(run).start();
    }
    public static void main(String[] args) {
        // 调用startThread方法,方法的参数是一个函数式接口,所以可以使用匿名内部类
        startThrea(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"--> 多线程启动了");
            }
        });

        // 使用Lambda表达式
        startThrea(() -> {
            System.out.println(Thread.currentThread().getName()+"--> 多线程开启了");
        });


    }
}

If the return value is a function of process type interface, it can be returned directly to a Lambda expression. When it is desired by a method, to obtain a java.util.Comparatoran object as interface type sorter, you can call the acquisition method.

import java.util.Arrays;
import java.util.Comparator;

public class Demo02Comparator {
    // 定义一个方法,方法的返回值类型使用函数式接口Comparator
    public static Comparator<String> getComparator() {
        // 方法的返回值是一个接口,我们可以返回这个接口的匿名内部类
       /*return new Comparator<String>() {
           // 按照字符串的降序排序
           @Override
           public int compare(String o1, String o2) {
              return o2.length() - o1.length();
           }
       };*/
       // 方法的返回值是一个接口,所以我们可以使用Lambda表达式
        /*return (String o1, String o2) -> {
            return o2.length() - o1.length();
        };*/
        // 进一步优化
        return (o1,o2) -> o2.length() - o1.length();
    }
    public static void main(String[] args) {
        String[] arr = {"111", "2222", "333333333", "44444"};
        System.out.println("排序前:");
        System.out.println(Arrays.toString(arr));
        System.out.println("排序后:");
        Arrays.sort(arr, getComparator());
        System.out.println(Arrays.toString(arr));

    }
}

3. The common function interface

3.1 Supplier <T>Interface

  • java.util.function.Supplier <T>interface contains only a non-reference method:
    • T get(): Used to obtain a generic parameter specifies the type of object data.
  • Supplier <T>interface is called production interfaces, generic interface to specify what type, then the get method interface what type of data is generated.

  • Examples

/*
Supplier<T>接口的使用
 */
import java.util.function.Supplier;

public class DemoSupplier {
    // 定义一个方法,方法的参数传递Supplier<T>接口,泛型指定为String,get方法就返回一个String
    public static String getString(Supplier<String> sup) {
        return sup.get();
    }
    public static void main(String[] args) {
        // 调用getString方法,方法的参数是一个Supplier<T>接口,即函数式接口,可以使用Lambda表达式
        // 重写其中的 get方法
        String s1 = getString(() -> {
            return "胡歌";
        });
        System.out.println(s1);

        // 优化Lambda表达式
        String s2 = getString(() -> "胡歌");
        System.out.println(s2);
    }
}

Exercise: Find the maximum array elements

import java.util.function.Supplier;

/*
    练习:求数组元素的最大值
        使用Supplier接口作为方法参数类型,通过Lambda表达式找出int型数组的最大值
        提示:接口的泛型使用 java.lang.Interger类
 */
 


public class DemoSupplierTest {
    /*
        定义一个方法,用于获取 int型数组的最大值,方法的参数传递Supplier<T>接口
        泛型使用 Integer
     */
    public static int getMax(Supplier<Integer> sup) {
        return sup.get();
    }
    public static void main(String[] args) {
        // 定义一个数组
        int[] arr = {12, 21, 100, 999, 8080, 1321, 10000};
        // 调用 getMax方法,方法的参数传递 Lambda表达式
        int maxValue = getMax(() -> {
          int max = arr[0];
            for (int i = 1; i < arr.length; i++) {
               if (max < arr[i]) {
                   max = arr[i];
               }
            }
            return max;
        });
        System.out.println("数组中元素的最大值为:"+maxValue);
    }
}

3.2 Consumer <T>Interface

  • java.util.function.Consumer <T>the interface is just the Supplier <T>Interface contrary, it is not a data production, but consumption data, the data type of the generic decision.
  • Comsumer interfaces include abstract methods: void accept(T t), which means consumption data is designated as a generic.
  • Comsumer interface is a consumer-oriented interfaces, generic specify what type, you can use the method accept what type of data consumption, as to how specific consumption (use), you need to customize (output, calculated ......)

  • Examples

import java.util.function.Consumer;

public class DemoComsumer {
    /*
        定义一个方法,参数:字符串和 Consumer<T>接口,泛型指定 String
        用来使用 Consumer接口消费字符串
     */
    public static void consume(String name, Consumer<String> con) {
        con.accept(name);
    }

    public static void main(String[] args) {
        consume("赵丽颖", (String name) -> {
            // 消费方式 打印输出
            // System.out.println(name);
            // 消费方法 反转
            /*
                StringBuilder是一个字符串缓冲区,里面有一个方法
                reverse方法可以将此字符序列反转,再使用 toString方法转换成String类
             */
            String rename = new StringBuilder(name).reverse().toString();
            System.out.println(rename);
        });
    }
}

The default method: andThen

If a method parameters and return values are Consumertype, the effects can be achieved: consumption data, the first thing to do an operation, then do an operation, implemented as a combination (connection), but this method is Consumerdefault method interface andThenmethod, JDK source code following formula:

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }

Note:
java.util.ObjectsThe requireNonNullstatic method will take the initiative to throw in the argument is null NullPointerExceptionexception. This eliminates the need for rewriting the if statement and throws null pointer exception trouble.

  • Example:
import java.util.function.Consumer;

/*
    Consumer接口的默认方法:andThen
    作用:需要两个 Consumer接口,可以把两个Consumer接口组合到一起,对数据进行消费

    例如:
        Consumer<String> con1;
        Consumer<String> con2;
        String s= "Hello";

        con1.accept(s);
        con2.accpet(s);
        这两行等价于
        con1.andThen(con2).accept(s);
    注:谁写前边,谁先消费

 */
public class DemoAndThen {
    /*
        定义一个方法,参数传递一个字符串和两个 Consumer接口,泛型都使用 String
     */
    public static void method(String s, Consumer<String> con1, Consumer<String> con2) {
//        con1.accept(s);
//        con2.accept(s);
        con1.andThen(con2).accept(s);

    }

    public static void main(String[] args) {
        String s = "Hello";
        method(s,
                (t) -> {
                    // 消费方式:把字符串变成大写
                    System.out.println(s.toUpperCase());
                },
                (t) -> {
                    // 消费方式:把字符串变成小写
                    System.out.println(s.toLowerCase());
                }
        );
    }
}

Exercise: formatted print information

import java.util.function.Consumer;

/*
    练习:
        字符串数组中有多条信息,请按照格式“姓名:xx。性别:xx。"的格式将信息打印出来
        要求将打印姓名的动作作为第一个Consumer接口的实例
        将打印性别的动作作为第二个 Consumer接口的实例
 */
public class AndThenTest {
    /*
        定义一个方法,参数为一个字符串数组,两个Consumer接口,泛型都使用String
     */
    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) {
        String[] arr = {"迪丽热巴,女", "古力娜扎,女", "马儿扎哈,男"};
        printInfo(arr,
                (message) -> {
                    // 对字符串进行切割,获取姓名
                    String name = message.split(",")[0];
                    System.out.print("姓名:" + name + "。");
                },
                (message) -> {
                    // 对字符串进行切割,获取性别
                    String sex = message.split(",")[1];
                    System.out.println("性别:" + sex + "。");
                });
    }
}

3.3 Predicate <T>Interface

  • java.util.function.Predicate <T>Interface
  • Effect: for data of a data type determination, the result returns a boolean
  • Predicate interfaces include an abstract method:
    • boolean test(T t): To judge the specified data type
    • result:
      • Eligible returns true
      • Does not meet the conditions, return false
  • Example:
import java.util.function.Predicate;

public class DemoPredicate {
    /*
        定义一个方法,参数传递一个字符串
        和一个Predicate接口,泛型使用String
        使用Predicate中的方法 test对字符串进行判断,并把判断的结果返回
     */
    public static boolean checkString(String s, Predicate<String> pre) {
        return pre.test(s);
    }

    public static void main(String[] args) {
        String s = new String("abcdef");
        // 调用checkString方法,函数式接口,使用Lambda表达式
        /*boolean b = checkString(s, (str) -> {
            return s.length() > 5;
        });*/

        // 对Lambda表达式进行优化
        boolean b = checkString(s, str -> str.length() > 5);
        System.out.println(b);

    }
}

The default method: and

  • JDK source code:
default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
  • Example:
import java.util.function.Predicate;

/*
    需求:
        判断一个字符串,有两个判断条件
        1. 字符串的长度是否大于5
        2. 字符串中是否包含a
    两个条件必须同时满足,我们就可以使用 && 运算符连接
 */
public class DemoPredicate_And {
    public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2) {
        return pre1.and(pre2).test(s);
        // 等价于 return pre1.test(s) && pre2.test(s);
    }

    public static void main(String[] args) {
        String s = "I Love Java!";
        boolean b = checkString(s, (String str) -> {
            // 对字符串长度是否大于5进行判断
            return str.length() > 5;
        }, (String str) -> {
            // 对字符串中是否包含a进行判断
            return str.contains("a");
        });
        System.out.println(b);
    }

}

The default method: or

  • JDK source code:
default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

The default method: negate

  • JDK source code:
 default Predicate<T> negate() {
        return (t) -> !test(t);
    }

Exercise: Screening information collection

import java.util.ArrayList;
import java.util.function.Predicate;

/*
题目:
    数组当中有多条"姓名+性别"的信息如下:
    String[] array = {"迪丽热巴,女", "古力娜扎,女", "马儿扎哈,男", "赵丽颖, 女"}; 请通过Predicate接口的拼装,将符合要求的字符串筛选到ArrayList集合中
    筛选条件须同时满足:
    1. 必须为女生
    2,名字为4个子
分析:
    1.有两个判断条件,所以需要使用两个Predicate接口
    2.必须同时满足两个条件,所以可以使用 and方法

 */
public class PredicateTest {
    public static ArrayList<String> filter(String[] arr, Predicate<String> pre1, Predicate<String> pre2) {
        // 创建一个ArrayList集合,存储过滤之后的信息
        ArrayList<String> list = new ArrayList<>();
        for (String s : arr) {
            // 使用and进行与操作
            boolean b = pre1.and(pre2).test(s);
            // 如果同时满足条件
            if (b) {
                list.add(s);
            }
        }
        // 返回过滤之后的集合
        return list;
    }

    public static void main(String[] args) {
        String[] array = {"迪丽热巴,女", "古力娜扎,女", "马儿扎哈,男", "赵丽颖, 女"};

        // 调用filter方法,使用Lambda表达式
        ArrayList<String> list = filter(array, (String s) -> {
            // 对是否是女生进行判断
            return s.split(",")[1].equals("女");

        }, (String s) -> {
            // 对名字是否是四个字进行判断
            return s.split(",")[0].length() == 4;

        });
        // 对过滤之后的集合进行输出
        for (String s : list) {
            System.out.println(s);
        }
    }
}

3.4 Function <T, R>Interface

  • java.util.function.Function <T,R>interface is used according to a type of data, another type of data obtained. The former is called pre-conditions, which is referred to as post-conditions.
  • Function interface to abstract the most important methods are: R apply(T t)obtaining the results according to the type of the parameter R type T.
  • For example usage scenarios: converting type Integer String type.

Note:
Function preconditions and postconditions generics Generics are the same.

  • Example:
import java.util.function.Function;
public class DemoFunction {
    /*
        定义一个方法,
        方法的参数传递一个字符串类型的整数
        方法的参数传递一个Function<String, Integer>类型的接口
        使用Function接口中的方法apply,把字符串类型的整数转换为Integer类型

     */
    public static Integer change(String s, Function<String, Integer> fun) {
        Integer in = fun.apply(s);
        // int in = fun.apply(S); // 自动拆箱 Integer --> int
        return in;
    }

    public static void main(String[] args) {
       int in =  change("123", (String s) -> {
           return Integer.parseInt(s);
        });
        System.out.println(in + 1);
    }
}

The default method: andThen

  • Function interface default method andThen: used for combining operation.

  • Examples

import java.util.function.Function;

/*
    需求:
        把String类型的"123"转换为Integer类型,再加上10
        把Integer类型转换为String类型
    分析:
        转换了两次
        1. String --> Integer
        Function<String, Integer> fun1
        Integer in = fun1.apply("123") + 10;
        2. Integer --> String
        Function<Integer, String> fun2
        String s = fun2.apply(in);
    使用andThen方法,把两次转换组合在一起使用
 */
public class Function_AndThen {
    public static void change(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {
        String str = fun1.andThen(fun2).apply(s);
        System.out.println(str);

    }

    public static void main(String[] args) {
/*
        change("123", (String s) -> {
            // String --> Integer
             return Integer.parseInt(s) + 10;
        }, (Integer in) -> {
            // Integer --> String
             return in + " ";
        });
*/
        // 优化Lambda表达式
        change("1234", s -> Integer.parseInt(s) + 100, i -> i + " ");
    }

}

Exercise: stitching Custom Function Model

import java.util.function.Function;

/*
题目:
    String str = "赵丽颖,20";
    1.将字符串截取数字年龄部分,得到字符串
    2.将上一步的字符串转换为int类型的数字
    3.将上一步的int数字累加100,得到结果int数字

分析:
    1."赵丽颖,20" -> "20"
    2."20" -> 20
    3. 20 + 100 -> 120
 */
public class DemoFunctionTest {
    /*
        定义一个方法,参数传递字符串和三个Function接口
        Function<String, String>fun1
        Function<String, Integer>fun2
        Function<Integer, Integer>fun3
     */
    public static int change(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 str = "赵丽颖,20";

        int num = change(str, (String s) -> {
            return s.split(",")[1];
        }, (String s) -> {
            return Integer.parseInt(s);
        }, (Integer in) -> {
            return in + 100;
        });
        System.out.println(num);
    }
}

Guess you like

Origin www.cnblogs.com/blog-S/p/11517161.html