• 周四. 10 月 3rd, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

Java8 functional programming and lambda expression

King Wang

1 月 3, 2022

List of articles

      • Functional programming
      • JDK8 New interface features
      • The function interface
      • Method reference

Functional programming

Functional programming is more often a way of thinking in programming , It’s a methodology . The difference between functional programming and imperative programming is that : Functional programming is telling the code what you’re going to do , Imperative programming tells the code how to do it . In short , Functional programming is based on some syntax or call API To program .

for example , Find the smallest number in the integer array , Using command programming to achieve the following :

public static void main(String[] args){

int[] array={
1,2,3,4,5,6,7,8,9,10};
int minx=Integer.MAX_VALUE;
for(int a:array){

if(a<minx)
minx=a;
}
System.out.println(minx);
}

And using functional programming to achieve , It is simplified to the following code :

 int[] array = {
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int minx = IntStream.of(array).min().getAsInt();
System.out.println(minx);

We can see that , Imperative programming needs to implement its own specific logic , Functional programming, on the other hand, calls API It needs to be done , Write imperative code as a series of function calls , In functional programming, the code is more concise 、 Understandability , That’s one of the reasons for functional programming . So functional programming is about telling code what you’re going to do , Imperative programming tells the code how to do it , It’s a shift in thinking .

and lambda Expressions are the basis of functional programming , It’s very important :

stay Java I won’t support it lambda In terms of expression , We’re going to create a thread like this :

 new Thread(new Runnable() {

@Override
public void run() {

// TODO Auto-generated method stub
System.out.println("run() Method ");
}
}).start();

And use lambda expression :

 new Thread(() -> System.out.println("run()")).start();

lambda In a word, the expression completes the creation of the thread , It emphasizes the input and output of the function , And hide the internal implementation details , And it can receive functions as input ( Parameters ) And the output ( Return value ).

stay -> On the left is input , On the right is the output . The above code parameter is empty .

The lambda The function of an expression is to return Runnable Interface implementation object , This calls a method to get the instance object, similar to , Just write the implementation code directly into the lambda Expression .

JDK8 New interface features

  1. The function interface , An interface can only have one method that needs to be implemented , have access to FunctionalInterface Make a statement with comments

    @FunctionalInterface
    public interface InterfaceOne {
    
    int doubleNum(int i);
    }
    

    Use lambda Expression to obtain the implementation of the interface instance of several writing :

     InterfaceOne num1 = (i) -> i * 2;
    System.out.println(num1.doubleNum(10));
    InterfaceOne num2 = i -> i * 2;
    // Specify parameter type 
    InterfaceOne num3 = (int i) -> i * 2;
    InterfaceOne num4 = (int i) -> {
    
    System.out.println(i);
    return i * 2;
    };
    
  2. Default method for interface , Used to provide a default implementation . The default method is the same as that of a normal implementation class , have access to this keyword .

    @FunctionalInterface
    public interface InterfaceOne {
    
    int doubleNum(int i);
    }
    default int add(int x,int y){
    
    return x+y;
    }
    

    The reason why the default method feature is more important , It’s because we can use this feature to provide default implementations on some of the previously written interfaces , And it doesn’t affect any implementation classes or existing code . For example, we are most familiar with List Interface , stay JDK1.2 since List The interface has not changed any code , here we are 1.8 After using this new feature, we added some default implementations . This is because if there is no feature of the default method , The impact of modifying the interface code is huge , And with the default method , Adding a default implementation does not affect any code .

  3. When the interface has multiple inheritance , The problem of default method override may occur , In this case, the default method implementation of which interface should be specified .

    @FunctionalInterface
    public interface InterfaceOne {
    
    int doubleNum(int i);
    default int add(int x, int y) {
    
    return x + y;
    }
    }
    @FunctionalInterface
    interface InterfaceTwo {
    
    int doubleNum(int i);
    default int add(int x, int y) {
    
    return x + y;
    }
    }
    @FunctionalInterface
    interface InterfaceThree extends InterfaceOne, InterfaceTwo {
    
    // Specifies the default method implementation of which interface to use 
    @Override
    default int add(int x, int y) {
    
    return InterfaceOne.super.add(x, y);
    }
    }
    

    The function interface

    Interface Input parameters Return type explain
    Predicate T boolean Assertion
    Consumer T / Consume a data
    Function<T,R> T R Input T, Output R
    Supplier / T Provide a data
    UnaryOperator T T One variable function ( The input and output types are the same )
    BiFunction<T,U,R> (T,U) R A function with two input parameters
    BinaryOperator (T,T) T Dual function ( The input and output types are the same )

    The most common one is Function Interface , This interface saves us some unnecessary function interfaces . Use the following example to illustrate Function Interface :

    public class TestFunction {
    
    public static void main(String[] args) {
    
    Account account = new Account("FEEL", 9999999);
    Function<Long, String> func = i -> new DecimalFormat("#,###").format(i);
    account.show(func);
    }
    }
    class Account {
    
    private String name;
    private long balance;
    public Account(String name, long balance) {
    
    this.name = name;
    this.balance = balance;
    }
    public void show(Function<Long, String> func) {
    
    System.out.println(name + " The account balance of : " + func.apply(this.balance));
    }
    }
    

    Output is :

    FEEL The account balance of : 9,999,999

If not used Function Interface , You need to define your own interface , And chain operations are not supported .

@FunctionalInterface
interface Format {

String format(long i);
}
class Account {

private String name;
private long balance;
public Account(String name, long balance) {

this.name = name;
this.balance = balance;
}
public void show(Format fm) {

System.out.println(name + " The account balance of : " + fm.format(balance));
}
}
public class Test_No_Function {

public static void main(String[] args) {

Account account = new Account("FEEL", 999999999);
Format fm = i -> new DecimalFormat("#,###").format(i);
account.show(fm);
}
}

Here is Predicate and Consumer Use of interfaces :

public static void main(String[] args) {

// Assertion function interface 
Predicate<Integer> p = i -> i > 0;
System.out.println("1>0? " + p.test(1));
// Consumer function interface 
Consumer<String> consumer = System.out::println;
System.out.println("Hello Consumer Interface!");
}

Output results :

1>0? true
Hello Consumer Interface!

These interfaces generally encapsulate the basic types , So you don’t need to specify generics when using base types :

public static void main(String[] args){

// Assertion function interface 
IntPredicate IP=i->i>0;
System.out.println(IP.test(1));
// Consumer function interface 
IntConsumer ic=(v)->System.out.println(" Input integer :"+v);
ic.accept(1999);
}

Output results :

true
Input integer :1999

Here’s how to use some other interfaces :

public static void main(String[] args) {

// Provide data interface 
Supplier<Integer> supplier = () -> 10;
System.out.println(" The data provided is : " + supplier.get());
// Univariate function interface 
UnaryOperator<Integer> unaryOperator = i -> i >> 1;
System.out.println(" The result of the calculation is : " + unaryOperator.apply(10));
// Binary function interface 
BinaryOperator<Integer> binaryOperator = (a, b) -> a * b;
System.out.println(" The result of the calculation is : " + binaryOperator.apply(10, 10));
}

The output is :

 The data provided is : 10
The result of the calculation is : 5
The result of the calculation is : 100

Method reference

We usually use them lambda Expression to create anonymous methods, but sometimes you just need to call an existing method . as follows :

Arrays.sort(array,(s1,s2)->s1.compareToIgnoreCase(s2));

And in the Jdk8 in , This can be simplified with a new feature lambda expression :

Arrays.sort(array,String::compareToIgnoreCase);

This line is called Method Reference( Method reference ), Its standard form is :

Class name :: Method name ::( Just write the method name , There’s no need to write brackets )

Four forms of method references :

type Example Code example Corresponding lambda expression
Reference static methods ContainingClass::staticMethodName String::valueOf (s)->String.valueOf(s)
An instance method that refers to an object containingObject::instanceMethodName x::toString() ()->this.toString()
An instance method that refers to any object of a certain type ContainingType::methodName String::toString (s)->s.toString
Reference construction method ClassName::new String::new ()->new String()

Define the entity class as follows :

package com.demo.after;
/**
* @author bushizhe
* @Time 2019 year 5 month 21 Japan Afternoon 4:38:56
* @Description
*/
public class FEEL {

private String name = "FEEL";
private int age = 21;
public FEEL() {

}
public FEEL(String name) {

this.name = name;
}
public FEEL(String name, int age) {

this.name = name;
this.age = age;
}
public static void show(FEEL feel) {

System.err.println(feel.name + " This year, " + feel.age + " Year old !!");
}
public int getAge(int age) {

System.out.println(name + " Age :" + age);
return age + 10;
}
@Override
public String toString() {

return "FEEL [name=" + name + ", age=" + age + "]";
}
}

Call method in entity class through method reference :

package com.demo.after;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.function.Supplier;
/**
* @author bushizhe
* @Time 2019 year 5 month 21 Japan Afternoon 4:44:20
* @Description
*/
public class TestMethod {

public static void main(String[] args) {

// Method reference , Call print method 
Consumer<String> consumer = System.out::println;
consumer.accept(" Data received :");
// Static method reference 
Consumer<FEEL> consumer2 = FEEL::show;
consumer2.accept(new FEEL("FEEL", 20));
// Instance method reference , Reference through an object instance 
FEEL feel = new FEEL();
IntUnaryOperator func = feel::getAge;
System.out.println(" Ten years later :" + func.applyAsInt(20) + " year ");
// A reference to a nonparametric constructor ,
Supplier<FEEL> supplier = FEEL::new;
System.out.println(" Created a new object " + supplier.get());
// Method references with parameter constructors 
BiFunction<String, Integer, FEEL> func2 = FEEL::new;
System.out.println(" Created a new object " + func2.apply("FLING", 20));
}
}

Output results :

Data received :
FEEL This year, 20 Year old !!
FEEL Age :20
Ten years later :30 year
Created a new object FEEL [name=FEEL, age=21]
Created a new object FEEL [name=FLING, age=20]

发表回复