02 | Java voice advanced | day12 [! ]_Functional interface, functional programming, common functional interface (Supplier, Consumer, Predicate, Function)

Keywords: Lambda Java Programming Google

Chapter 1 functional interface

1.1 the concept of functional interface & the definition of functional interface

  1. In Java, functional interface refers to an interface with only one abstract method.
  2. Syntax sugar refers to the code syntax which is more convenient to use but the principle is unchanged.
    • For each is the syntax sugar of the iterator.
    • From the application layer: Lambda can be used as the syntax sugar of anonymous inner class
      • But the two principles are different.
      • Anonymous inner classes generate. class files ($named), but Lambda does not
      • So Lambda is efficient
  • Note: functional interface: an interface with only one abstract method is called functional interface
    • Of course, the interface can contain other methods (default, static, private)

1.2 format of functional interface

1.3 @ functional interface annotation of functional interface

  1. @Functional interface annotation - > write functional interface in the future
    • Function: can detect whether the interface is a functional interface
      • Yes: compilation succeeded
      • No: compilation failed (there are more than one abstract method without abstract method in the interface)

1.4 use of functional interface

  1. Use of functional interface: generally, it can be used as the parameter and return value type of the method

Chapter II functional programming

2.1 delayed execution of lambda

2.1.1 log cases of performance waste

  1. Journal:
    • It can help us quickly locate problems and record the process of program running, so as to monitor and optimize the project
  2. Log case
    • Some performance waste problems found in the following code [!]
    • Call the showLog method. The second parameter passed is a concatenated string
    • First, splice the strings, and then call the showLog method
    • If the log level passed in the showLog method is not level 1
    • Then it won't be such a concatenated string
    • So it feels like strings are white spliced, and there is waste
    public class Demo01Logger {
        //Define a method to display log information based on the level of the log
        public static void showLog(int level, String message){
            //Judge the level of the log. If it is level 1, the log information will be output
            if(level == 1){
                System.out.println(message);
            }
        }
    
        public static void main(String[] args) {
            //Define three log information
            String msg1 = "Hello";
            String msg2 = "World";
            String msg3 = "Java";
    
            //Call the showLog method to pass the log level and log information
            showLog(1, msg1 + msg2 + msg3);
        }
    }
    
    //Result:
    HelloWorldJava

2.1.2 use Lambda to optimize log cases

  1. Optimizing log cases with Lambda
    • Lambda features: delayed loading [!]
    • The premise of Lambda is that there must be a functional interface [!]
  2. Use Lambda expression to pass as parameter, just pass the parameter to showLog method
    1. Only if the conditions are met, the log level is level 1
      • Will call the method buildmessage in the interface MessageBuilder
      • String splicing
    2. If the conditions are not met, the log level is not level 1
      • Then the method buildmessage in the MessageBuilder interface will not execute
      • So the concatenated string code will not execute either
    • So there's no performance waste
    //Defined functional interface: MessageBuilder.java
    @FunctionalInterface
    public interface MessageBuilder {
        //Define an abstract method for splicing messages, and return the spliced information
        public abstract String builderMessage();
    }
    
    //Main method: Demo02Lambda.java
    public class Demo02Lambda {
        //Define a method to display the log, the level of the method's parameter delivery log and the MessageBuilder interface
        public static void showLog(int level, MessageBuilder mb){
            //Judge the level of the log. If it is level 1, call the buildmessage method in the MessageBuilder interface
            if(level == 1){
                System.out.println(mb.builderMessage());
            }
        }
    
        public static void main(String[] args) {
            //Define three log information
            String msg1 = "Hello";
            String msg2 = "World";
            String msg3 = "Java";
    
            //Call the showLog method. The parameter MessageBuilder is a functional interface, so you can pass Lambda expressions
            showLog(1, () -> {
                System.out.println("Do not execute if the conditions are not met");
                //Returns a concatenated string
                return msg1 + msg2 + msg3;
            });
    
        }
    }
    //Results: (when satisfied)
    //Do not execute if the conditions are not met
    HelloWorldJava
    //Result: (not satisfied)
    

2.2 functional interface as the parameter of method case

    /*
        For example, the java.lang.Runnable interface is a functional interface,
        If you have a startThread method that uses this interface as a parameter, you can use Lambda to pass parameters.
        In fact, there is no essential difference between this situation and the Thread class's constructor parameter of Runnable.
     */
    public class Demo01Runnable {
        //Define a method startThread. The parameters of the method use the function interface Runnable
        public static void startThread(Runnable run){
            //Turn on Multithreading
            new Thread(run).start();
        }
    
        public static void main(String[] args) {
            //Call the startThread method. The parameter of the method is an interface. Then we can pass the anonymous inner class of the interface
            startThread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "-->" + "Thread started");   //currentThread() currently executing thread
                }
            });
    
            //Call the startThread method. The parameter of the method is a functional interface, so you can pass the Lambda expression
            startThread(() -> {
                System.out.println(Thread.currentThread().getName() + "-->" + "Thread started");   //currentThread() currently executing thread
            });
    
            //Optimizing Lambda
            startThread(() -> System.out.println(Thread.currentThread().getName() + "-->" + "Thread started"));
        }
    }
    
    //Result:
    Thread-0-->Thread started
    Thread-1-->Thread started
    Thread-2-->Thread started

2.3 case of function interface as return value type of method

    /*
        If the return value type of a method is a functional interface, a Lambda expression can be returned directly.
        When you need to obtain an object of java.util.Comparator interface type as a sorter through a method, you can call this method to obtain.
     */
    public class Demo02Comparator {
        //Define a method whose return value type uses the function interface Comparator
        public static Comparator<String> getComparator(){
            //The return value type of method is an interface, so we can return the anonymous inner class of this interface
            /*return new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    //Sort strings in descending order
                    return o2.length()-o1.length();
                }
            };*/
    
            //The return value type of the method is a functional interface, so we can return a Lambda expression
            /*return (String o1, String o2) -> {
                return o2.length()-o1.length();
            };*/
    
            //Continue to optimize Lambda
            return (o1, o2) -> o2.length()-o1.length();
        }
    
        //Main function
        public static void main(String[] args) {
            //Create an array of strings
            String[] arr = {"aaa", "bb", "cccccc", "ddddddddddd"};
            //Output string before sorting
            System.out.println(Arrays.toString(arr));   //[aaa, bb, cccccc, ddddddddddd]
            //Call the sort method in Arrays to sort the string array
            Arrays.sort(arr, getComparator());
            //Output sorted string
            System.out.println(Arrays.toString(arr));   //[ddddddddddd, cccccc, aaa, bb]
        }
    }
    
    //Result:
    [aaa, bb, cccccc, ddddddddddd]
    [ddddddddddd, cccccc, aaa, bb]

Chapter 3 common functional interfaces

3.1 common functional interface (supplier interface)

  1. The java.util.function.Supplier interface contains only one method without parameters
    • T get(). Used to get object data of the type specified by a generic parameter.
    • The Supplier interface is called a production interface. If you specify the generic type of the interface, the get method in the interface will produce the data of what type
    • Produce a data
    public class Demo01Supplier {
        //Define a method. The parameter of the method passes the supplier < T > interface. If the generic type executes String, the get method will return a String
        public static String getString(Supplier<String> sup){
            return sup.get();
        }
    
    
        public static void main(String[] args) {
            //Call the getString method. The parameter Supplier of the method is a functional interface, so you can pass the Lambda expression
            String s = getString(() -> {
                //Produce a string and return
                return "Hu Ge";
            });
            System.out.println(s);
    
            //Optimizing Lambda
            String s2 = getString(() -> "Google");
            System.out.println(s2);
        }
    }
    //Result:
    //Hu Ge
    //Google

3.2 Supplier interface exercise - finding the maximum value of array elements

    public class Demo02Test {
        //Define a method to get the maximum value of the elements in the array of type int, pass the Supplier interface for the parameters of the method, and use Integer for generics
        public static int getMax(Supplier<Integer> sup){
            return sup.get();
        }
    
        public static void main(String[] args) {
            //Define an array of type int and assign
            int[] arr = {100, 22, -33, 88, 40, 0};
            //Call the getMax method. The parameter Supplier of the method is a functional interface, so you can pass the Lambda expression
            int maxValue = getMax(() -> {
                //Gets the maximum value of the array and returns
                // Define a variable, assign the first element in the array to the variable, and record the maximum value of the element in the array
                int max = arr[0];
                //Traverse the array to get other elements in the array
                for (int i : arr) {
                    //Compare with maximum using other elements
                    if (i > max) {
                        //If i is greater than max, replace Max as the maximum
                        max = i;
                    }
                }
                return max;
            });
            System.out.println("The largest elements in the array are:" + maxValue);
        }
    
    }
    
    //Result:
    //The largest element in the array is: 100

3.3 common functional interface (Consumer interface)

  1. The java.util.function.Consumer interface is the opposite of the Supplier interface,
    • Instead of producing a data, it consumes a data whose data type is determined by generics.
    • The Consumer interface contains the abstract method void accept (t t t), which means to consume data of a specified generic type.
  2. The Consumer interface is a Consumer interface. You can use the accept method to consume data of whatever type the generic implementation type is
    • As for how to consume (use), you need to customize (output, calculate )
    • Note: no return value
    public class Demo01Consumer {
        /*
            Define a method
            Method to pass the name of a string
            The parameter of the method passes the Consumer interface, and the generic uses String
            Names that can consume strings using the Consumer interface
         */
        public static void method(String name, Consumer<String> con){
            con.accept(name);
        }
    
        public static void main(String[] args) {
            //Call the method method method and pass the string name. The other parameter of the method is the Consumer interface, which is a functional interface, so you can pass the Lambda expression
            method("Zhao Liying", (String name) -> {
                //Consume the passed string
                //Consumption mode: direct output
                //System.out.println(name); / / Zhao Liying
    
                //Consumption pattern: reversal
                String reName = new StringBuilder(name).reverse().toString();   //Chain programming
                System.out.println(reName);
            });
        }
    }
    
    //Result:
    //Ying Li Zhao

3.4 default method of consumer interface andThen

  1. The default method of the Consumer interface andThen
    • Function: two Consumer interfaces are required, which can be combined to consume data
    • Note: multiple interfaces can also be connected together
         con1.andThen(con2).andThen(con3).accept(s);
    
  2. For example:
        Consumer<String> con1
        Consumer<String> con2
        String s = "hello";
        
        con1.accept(s);
        con2.accept(s);
        
        Connect two Consumer interfaces for consumption
        con1.andThen(con2).accept(s); who writes first and who consumes first
    
    • Note: who writes first and who consumes first
    public class Demo02AndThen {
        //Define a method. The parameters of the method pass a string and two Consumer interfaces. The generics of the Consumer interface use strings
        public static void method(String s, Consumer<String> con1, Consumer<String> con2){
            //Use common methods first
            //con1.accept(s);
            //con2.accept(s);
            //Use the default method andThen in the interface
            //Connect two Consumer interfaces for consumption
            con1.andThen(con2).accept(s); //Who writes first and who consumes first
        }
    
    
        public static void main(String[] args) {
            //Call method method, pass a string, two Lambda expressions
            method("Hello", (s) -> {
                //Consumption method, converting string to uppercase output
                System.out.println(s.toUpperCase());
            }, (s) -> {
                //Consumer method, converting string to lowercase output
                System.out.println(s.toLowerCase());
            });
        }
    }
    
    //Result:
    HELLO
    hello

3.5 Consumer interface exercise string splicing output

    public class Demo03Test {
        //Define a method to pass an array of String type and two consumer interfaces. Generics use String
        public static void printInfo(String[] arr, Consumer<String> con1, Consumer<String> con2){
            //Traversal string array
            for (String message : arr) {
                //Using the andThen method to connect two Consumer interfaces, consuming strings
                con1.andThen(con2).accept(message);
            }
        }
    
        public static void main(String[] args) {
            //Define an array of string types
            String[] arr = {"Di Ali Gerba,female", "Guli Nazha,female", "Mar Zaha,male"};
    
            //Call the printInfo method, passing an array of strings and two Lambda expressions
            printInfo(arr, (message) -> {
                //Consumption mode: cut message, get name and output in specified format
                String name = message.split(",")[0];    //String array index 0 saved name
                System.out.print("Full name:" + name);
            }, (message) -> {
                //Consumption mode: cut message, get gender, and output according to the specified format
                String sex = message.split(",")[1];    //Gender of string array index 1
                System.out.println(",Full name:" + sex + ". ");
            });
        }
    }
    
    //Result:
    //Name: delireba, name: female.
    //Name: gulinaza, name: female.
    //Name: malzaha, name: male.

3.6 common functional interface (Predicate) interface

  1. java.util.function.Predicate interface
    • Function: judge the data of a data type and return a boolean value
    • Can't store to collection, need customization - > just a judgment
    • Return value
  2. The Predicate interface contains an abstract method, test:
    • boolean test(T t): the method used to judge the data of the specified data type
      • Result:
        • Qualified, return true
        • If the condition is not met, return false
    public class Demo01Predicate {
        /*
            Define a method
            Parameter to pass a String of type String
            Pass a Predicate interface, generic uses String
            Use the method test in Predicate to judge the string and return the result
         */
        public static boolean checkString(String s, Predicate<String> pre){
            return pre.test(s);
        }
    
        public static void main(String[] args) {
            //Define a string
            String s = "abcde";
    
            //Call the checkString method to verify the string, and pass the string and Lambda expression
            /*boolean b = checkString(s, (String str) -> {
                //Judge the string passed by the parameter, judge whether the length of the string is greater than 5, and return the result
                return str.length() > 5;
            });*/
    
            //Optimize Lambda expressions
            boolean b = checkString(s, str -> str.length() > 5);
    
            System.out.println(b);
        }
    }
    
    //Result:
    false

3.7 predict interface: the three default methods

  1. Logical expression: conditions that can connect multiple judgments
    • &&: and operator, false if false
    • ||: or operator, true if true
    • !: non (negate) operator, false if not true, true if not false
  2. There is a method and in the Predicate interface to represent and relate, which can also be used to connect two judging conditions
        default Predicate<T> and(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> this.test(t) && other.test(t);
        }
    
    • The two inner judgment conditions of the method are also connected by the & & operator
  3. Exercise requirements: judge a string, with two conditions
    1. Determine whether the length of the string is greater than 5
    2. Determine whether the string contains a
    • If the two conditions must be met at the same time, we can use the & & operator to connect the two conditions
    public class Demo02Predicate_and {
        /*
            Define a method, parameters of the method, pass a string
            Pass two Predicate interfaces
                One is used to determine whether the length of the string is greater than 5
                A is used to determine whether the string contains a
                Both conditions must be met at the same time
         */
        public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
            return pre1.and(pre2).test(s);  //Equivalent to return pre1.test (s) & & pre2.test (s);
        }
    
        public static void main(String[] args) {
            //Define a string
            String s = "abcdef";
            //Call checkString method, pass string and two Lambda expressions
            boolean b = checkString(s, (String str) -> {
                //Determine whether the length of the string is greater than 5
                return str.length() > 5;
            }, (String str) -> {
                //Determine whether the string contains a
                return str.contains("a");
            });
            System.out.println(b);
        }
    }
    
    //Result:
    true

3.8 predict interface, one of the three default methods

  1. The Predicate interface has a method or, representation or relationship, which can also be used to connect two judgment conditions
        default Predicate<T> or(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) || other.test(t);
        }
    
  2. The two inner judgment conditions of the method are also connected by the | | - operator
  3. Exercise: requirement: judge a string with two conditions
    1. Determine whether the length of the string is greater than 5
    2. Determine whether the string contains a
    • If one condition is satisfied, we can use the ðž“œ operator to connect the two conditions
    public class Demo03Predicate_or {
        /*
                Define a method, parameters of the method, pass a string
                Pass two Predicate interfaces
                    One is used to determine whether the length of the string is greater than 5
                    A is used to determine whether the string contains a
                    One condition is satisfied
             */
        public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
            //return pre1.test(s) || pre2.test(s);
            return  pre1.or(pre2).test(s);//Equivalent to return pre1.test (s) | pre2.test (s);
        }
    
        public static void main(String[] args) {
            //Define a string
            String s = "bcgggg";
            //Call checkString method, pass string and two Lambda expressions
            boolean b = checkString(s,(String str)->{
                //Determine whether the length of the string is greater than 5
                return str.length()>5;
            },(String str)->{
                //Determine whether the string contains a
                return str.contains("a");
            });
            System.out.println(b);
        }
    }
    
    //Result:
    true

3.9 predict interface & negate (negative) of the three default methods

  1. There is a method "negate" in the Predicate interface, which also means "negate"
        default Predicate<T> negate() {
            return (t) -> !test(t);
        }
    
  2. Exercise requirement: judge whether the length of a string is greater than 5
    1. If the length of the string is greater than 5, return false
    2. Return true if the length of string is not greater than 5
    *So we can use the reverse sign to reverse the result of judgment
    public class Demo04Predicate_negate {
        /*
               Define a method, parameters of the method, pass a string
               Use the Predicate interface to determine if the length of a string is greater than 5
        */
        public static boolean checkString(String s, Predicate<String> pre){
            return pre.negate().test(s);    //Equivalent to return! Pre.test (s);
        }
    
    
        public static void main(String[] args) {
            //Define a string
            String s = "abc";
            //Call checkString method, pass string and Lambda expression
            /*boolean b = checkString(s, (String str) -> {
                return str.length() > 5;
            });*/
    
            //Optimizing Lambda
            boolean b = checkString(s, str -> str.length() > 5);
    
            System.out.println(b);
        }
    
    }
    
    //Result:
    true

3.10 predict interface exercise set information filtering

    public class Demo05Test {
        /*
            Define a method
            Method to pass an array of personnel information
            Pass two predict interfaces to filter the information in the array
            Store the information that meets the conditions in the ArrayList collection and return
         */
        public static ArrayList<String> filter(String[] arr, Predicate<String> pre1, Predicate<String> pre2){
            //Define an ArrayList collection to store filtered information
            ArrayList<String> listA = new ArrayList<>();
            //Traverse the array to get every piece of information in the array
            for (String s : arr) {  //It's arr, not listA
                //Use the method test in the Predicate interface to judge the obtained string
                boolean b = pre1.and(pre2).test(s);
                //Judge the obtained boolean value
                if(b){
                    //If the conditions are met, store the information in the ArrayList set
                    listA.add(s);
                }
            }
            //Return the set
            return listA;
        }
    
        public static void main(String[] args) {
            //Define an array to store strings
            String[] array = { "Di Ali Gerba,female", "Guli Nazha,female", "Mar Zaha,male", "Zhao Liying,female" };
            //Call the filter method, passing the string array and two Lambda expressions
            ArrayList<String> listA = filter(array, (String str) -> {
                //Must be a girl
                return str.split(",")[1].equals("female");
            }, (String str) -> {
                //The name is 4 words.
                return str.split(",")[0].length()==4;
            });
    
            //Ergodic set
            for (String s : listA) {
                System.out.println(s);
            }
        }
    }
    
    //Result:
    //Delireba, female
    //Gulinaza, female

3.11 common Function interface

  1. Java. Util. Function. Function < T, R >: interface is used to get data of one type from data of another type
    • The former is called pre condition, and the latter is called post condition.
  2. The main abstract method in Function interface is: R apply (t t t): get the result of type R according to the parameter of type T.
  3. Exercise: use a scenario such as converting a String type to an Integer type.
    public class Demo01Function {
        /*
            Define a method
            Method to pass an integer of type string
            The parameter of the method passes a Function interface, and the generic type uses < string, integer >
            Use the method apply in the Function interface to convert an Integer of string type to an Integer of Integer type
         */
        public static void change(String s, Function<String, Integer> fun){
            Integer in = fun.apply(s);  //Can also be written as int, auto unpacking integer - > int
            System.out.println(in);
        }
    
        public static void main(String[] args) {
            //Define an integer of type string
            String s = "1234";
            //Call the change method, pass the integer of string type, and Lambda expression
            /*change(s, (String str) -> {
                //Converts an Integer of type string to an Integer of type Integer
                return Integer.parseInt(str);
            });*/
            
            //Optimizing Lambda
            change(s, str -> Integer.parseInt(str));
        }
    }
    
    //Result: (Integer type)
    1234

3.12 Function interface default method and then

  1. The default method andThen: in Function interface is used for combination operation
  2. Demand:
    1. Convert "123" of String type to Inteter type, and add 10 to the converted result
    2. Convert the data of Integer type after adding to String type
  3. Analysis:
    • Changed twice
    1. The first time is to convert String type to Integer type
      • So we can use function < string, integer > fun1
        • Integer i = fun1.apply("123")+10;
    2. The second time is to convert Integer type to String type
      • So we can use function < integer, string > fun2
        • String s = fun2.apply(i);
    • We can use the andThen method to combine the two transformations
      • String s = fun1.andThen(fun2).apply("123");
      • First, call the apply method to convert the string to Integer
      • fun2 then calls the apply method to convert the Integer into a string
    public class Demo02Function_andThen {
        /*
            Define a method
            An integer of type string
            Parameters pass two more Function interfaces
                A generic uses function < string, integer >
                A generic uses function < integer, string >
         */
        public static void change(String s, Function<String, Integer> fun1, Function<Integer, String> fun2){
            String ss = fun1.andThen(fun2).apply(s);
            System.out.println(ss);
        }
    
        public static void main(String[] args) {
            //Define an integer of type string
            String s = "123";
            //Call the change method, passing a string and two Lambda expressions
            /*change(s, (String str) -> {
                //Convert string to integer + 10
                return Integer.parseInt(str) + 10;
            }, (Integer i) -> {
                //Convert an integer to a string
                return i + "";
            });*/
    
            //Optimizing Lambda
            change(s, str -> Integer.parseInt(str) + 10, i -> i + "");
        }
    }
    
    //Result:
    133

3.13 Function interface exercise - user defined function model splicing

  1. Analysis:
    1. Intercept the age part of the string to get the string;
      Function < string, string > "Zhao Liying, 20" - > "20"
    2. Convert the string of the previous step to a number of type int;
      Function<String,Integer> "20"->20
    3. Add up the int number of the previous step by 100 to get the result int number.
      Function<Integer,Integer> 20->120
    public class Demo03Test {
        /*
            Define a method
            Parameter passes a string containing the name and age
            Parameters are passed three more Function interfaces for type conversion
         */
        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) {
            //Define a string
            String str = "Zhao Liying,20";
            //Call change method, pass string and 3 Lambda expressions
            /*int num = change(str, (String s) -> {
                //Intercept the age part of the number from the string to get the string
                //"Zhao Liying, 20 "- >" 20“
                return s.split(",")[1];
            }, (String s) -> {
                //"20"->20
                return Integer.parseInt(s);
            }, (Integer i) -> {
                //20->120
                return i + 100;
            });*/
    
            //Simplified Lambda
            int num = change(str, s -> s.split(",")[1], s -> Integer.parseInt(s), i -> i + 100);
    
            System.out.println(num);
        }
    }
    
    //Result:
    120
Published 23 original articles, won praise 5, visited 356
Private letter follow

Posted by hippypink on Fri, 13 Mar 2020 19:10:04 -0700