Java object-oriented functional programming

1 Functional programming

In mathematics, a function is a set of calculation plans with input and output quantities, that is, "what is used to do something." Relatively speaking, object-oriented overemphasizes "things must be done in the form of objects", while functional thinking tries to ignore the complex syntax of object-oriented - emphasizing what to do rather than the form in which to do it.

1.1 What to do, not how to do it

  • For example:

new Thread(new Runnable(){
    @Override
    public void run(){
        //TODO things
    }
}).start();

Regarding the usage ​Runnable​of anonymous inner classes, several points can be analyzed:

  • The class​Thread​ requires ​Runnable​an interface as a parameter, and the abstract run method is the core used to specify the thread task content;
  • In order to specify the method body of run, we must create an implementation class of ​Runnable​the interface ;
  • In order to save the trouble of defining an ​Runnable​implementation class, we must use anonymous inner classes;
  • In the anonymous inner class, we must override and rewrite the abstract run method, so the method name, method parameters, and method return value have to be written again without errors;
  • In fact , probably only the run() method body is the most important key in the program.
  • What we really want to do is pass the code in the run method body to the Thread class and execute it.

think:

Do we really want to create an anonymous inner class object? No!

We just have to create an object in order to do this.

1.2 What is the essence of functional programming?

Passing a piece of code - this is our real purpose. Creating objects is just a method that has to be adopted due to object-oriented syntax. So, is there an easier way?

If we return our focus from "how to do" to the essence of "what to do", we will find that as long as the purpose can be better achieved, the process and form are not actually important.

One problem with anonymous inner classes is that even if the implementation of the anonymous inner class is very simple, such as an interface that only contains an abstract method, the syntax of the anonymous inner class still appears redundant.

Solution: You can use the lambda expression supported by JDK8. This expression is only implemented for an interface with an abstract method, and implements the interface function in the form of a concise expression as a method parameter.

new Thread(() -> System.out.println("Multi-threaded task execution!")).start();

The execution effect of this code is exactly the same as the one just now, and it can pass under compilation level 1.8 or higher. It can be seen from the semantics of the code: we start a thread, and the content of the thread task is specified in a more concise form.

There is no longer the shackles of "having to create interface objects", and there is no longer the burden of "abstract method overriding and rewriting", it's that simple!

1.3 Lambda expression

Basic syntax format of lambda expression

Arrows are used in statements to distinguish parameter lists and method bodies.

2 Functional interface

2.1 Is it possible to use lambdas instead of all anonymous inner classes?

Lambda expressions can be used instead of anonymous inner classes when there is only one abstract method in the interface. This is because lambda expressions are implemented based on functional interfaces.

The so-called functional interface refers to an interface with one and only one abstract method. Lambda expression is the embodiment of functional programming in Java. Only by ensuring that the interface has one and only one abstract method can lambda expression successfully deduce the implemented interface. method in.

2.2 Definition

In JDK8, the interface marked with the @FunctionalInterface annotation is a functional interface, and there is only one abstract method inside the functional interface.

Let’s take a look at the source code in the Runnable interface:

Note: The @FunctionalInterface annotation only explicitly marks the interface as a functional interface and forces the editor to perform stricter checks to ensure that the interface is a functional interface.

Some functional interfaces that existed before JDK8:

  • java.lang.Runnable
  • java.util.Comparater
  • java.io.FileFilter
  • java.lang.Reflect.InvocationHandler

Functional interface added in JDK8

The java.util.function package contains many classes to support functional programming in Java.

 

​​​​​​​

 

2.3 Simplification of Lambda expressions

The omitted writing method of lambda expression (further simplifying based on lambda expression)

1. If the method body code of the lambda expression has only one line of code, you can omit the curly braces and omit the semicolon!

2. If the method body code of the lambda expression has only one line of code, and if this line of code is a return statement, the return must be omitted and the semicolon must be omitted.

3. The parameter type can be omitted.

4. If there is only one parameter, the () outside the parameter can also be omitted.

In addition to the above simplification rules, lambda expressions can be further simplified using "method references".

public class TestOutter { 
  public static void main(String[] args) { 
    //Anonymous function writing method 
    new Thread(new Runnable() {      
      @Override 
      public void run() { 
        System.out.println("Thread 1 is started!") ; 
        
      } 
    }).start(); 
    
    //lambda writing method 
    new Thread(() -> {System.out.println("Thread 2 started!");}).start(); 
  } 
}

3 method reference

Note : When the body of the lambda expression has only one statement, the program can not only omit the curly braces containing the body, but also reference methods and constructors (that is, construction methods) through the English double colon "::" syntax format.

Function : It can further simplify the writing of lambda expressions. Its essence is to directly reference the existing methods in the main part of the lambda expression. The main difference is the reference to ordinary methods and constructor methods.

3.1 Class name refers to static method

Definition: The class name refers to the static method, which is the reference to the static method through the class name. The class can be a special class that comes with Java, or it can be a custom ordinary class.

Example citations are as follows:

//Define functional interface 
@FunctionalInterface 
interface Calcable{ 
  int calc(int num); 
} 

//Define a class and define a static method in the 
class class Math{ 
  public static int abs(int num){ 
    return num > 0 ? num : -num; 
  } 
} 

public class Example { 
  private static void printAbs(int num, Calcable calcable){ 
    System.out.println(calcable.calc(num)); 
  } 
  
  public static void main(String[] args) { 
    
    //1 , use anonymous inner class 
    printAbs(-8, new Calcable() {      
      @Override 
      public int calc(int num) { 
        return Math.abs(num); 
      } 
    }); 
    
    //2. Use lambda expression
    printAbs(-8, (num) -> {return Math.abs(num);}); 
    
    //3. Simplify lambda expression 
    printAbs(-9, num -> Math.abs(num)); 
    
    //4. Use method references to simplify lambda expressions 
    printAbs(-7, Math::abs); 
  } 
}

3.2 Object name reference method

Definition: The object name reference method refers to the reference to its method through the name of the instantiated object.

Example citations are as follows:

//Define functional interface 
@FunctionalInterface 
interface Utils{ 
  String calc(String str); 
} 

//Define a class and define a common method in the class 
class UpperUtil{ 
  public String toUpper(String str){ 
    return str.toUpperCase(); 
  } 
} 

public class Example2 { 
  private static void printUpper(String ori, Utils u){ 
    System.out.println(u.calc(ori)); 
  } 
  
  public static void main(String[] args) { 
    UpperUtil upper = new UpperUtil() ; 
    
    //1. Use anonymous inner class 
    printUpper("abc", new Utils() {      
      @Override 
      public String calc(String ori) { 
        return upper.toUpper(ori); 
      }
    }); 
    
    //2. Use lambda expression 
    printUpper("bcd", (ori) -> {return upper.toUpper(ori);}); 
    
    //3. Simplify lambda expression 
    printUpper("cde", ori - > upper.toUpper(ori)); 
    
    //4. Use method references to simplify lambda expressions 
    printUpper("def", upper::toUpper); 
  } 
}

3.3 Constructor reference method

Definition: refers to a reference to the constructor that comes with the class.

Example citations are as follows:

//Define functional interface 
@FunctionalInterface 
interface PersonBuilder{ 
  Person buildPerson(String name); 
} 

//Define a class, define a constructor and common methods in the 
class class Person{ 
  private String name; 
  
  public Person(String name){ 
    this. name = name; 
  } 
  
  public String getName(){ 
    return name; 
  } 
} 

public class Example3 { 
  private static void printName(String name, PersonBuilder buildPerson){ 
    System.out.println(buildPerson.buildPerson(name).getName()); 
  } 
  
  public static void main(String[] args) { 
    
    //1. Use lambda expression 
    printName("李思", (String name) -> {return new Person(name);});
    
    //2. Use the constructor reference method 
    printName("Zhang San", Person::new); 
  } 
}

3.4 Class names refer to common methods

Definition: refers to a reference to a common method of a common class through its class name.

Example citations are as follows:

//Define functional interface 
@FunctionalInterface 
interface Printable{ 
  void print(StringUtils su, String str); 
} 

//Define a class and method 
class StringUtils{   
  public void printUppercase(String str){ 
    System.out.println(str.toUpperCase( )); 
  } 
} 

public class Example4 { 
  private static void printUpper(StringUtils su, String str, Printable printable){ 
    printable.print(su, str); 
  } 
  
  public static void main(String[] args) { 
    //1. Use Anonymous inner class 
    printUpper(new StringUtils(), "abc", new Printable() {       
      @Override  
      public void print(StringUtils su, String str) {
        su.printUppercase(str);        
      } 
    });
     
    //2. Use lambda expression 
    printUpper(new StringUtils(), "bcd", (Object, t) -> Object.printUppercase(t)); 
    
    //3. Use method reference Method 
    printUpper(new StringUtils(), "def", StringUtils::printUppercase); 
  } 
}

Guess you like

Origin blog.csdn.net/QQ156881887/article/details/129191775