Introduction:

You can look at some of the new features of Java8, but you won’t normally use them.

The main content

  • Define interface methods using default and static
  • Lambda expressions
  • Method references
  • Built-in functional interfaces

The specific content

Define interface methods using default and static

It’s been 20 years since the beginning of Java, and it’s been 20 years since all developers know that Java interfaces are made up of global constants and abstract methods. But since the days of JDK1.8, this composition has changed. If you have an interface right now, that interface has generated 2W subclasses over time. One day, you realize that there are not enough methods in this interface, and you should add a method that implements exactly the same functionality for all the different subclasses. The original approach was to override the new method on each subclass. So we’re going to modify 2W subclasses. So to solve this problem, it is possible to define normal methods in the interface. However, if you want to define ordinary methods, you must explicitly use default to define them.

Example: ** Define the default method

public interface Message {  // Define the interface
    public void print(a);  // This is a method originally defined in an interface
    default void fun(a) {  // a common method is defined in the interface
        System.out.println("The method of destroying three views appeared!"); }}public class MessageImpl implements Messagee {
    @Override
    public void print(a) {
        System.out.println("Hello World !"); }}public class TestDemo {
    public static void main(String args[]) {
        Message msg = new MessageImpl();
        msg.fun();  // This method is defined in the interface}}Copy the code

The output

The method of destroying three views appeared!Copy the code

In addition to defining a method using default, you can also define a method using static, which means that the method can be called directly from the class name.

Example: ** Define static methods

public interface Message {  // Define the interface
    public void print(a);  // This is a method originally defined in an interface
    static void get(a) {
        System.out.println("Called directly from the interface!"); }}public class TestDemo {
    public static void main(String args[]) { Message.get(); }}Copy the code

The output

Directly called by the interface!Copy the code

One of the most important concepts in JDK1.8 is that inner classes can access method parameters without the final keyword. All of these new features completely break Java’s existing code composition.

Lambda expressions

  1. Analyze the causes of functional programming.
  2. Master the syntax of functional programming.

Lamda belongs to the concept of functional programming. Why do you need functional programming? If you want to understand the purpose of functional programming, you must analyze it through anonymous inner classes.

** Example: ** Anonymous inner class

public interface Message {
    public void print(a);
}

public class TestDemo {
    public static void main(String args[]) {
        fun(new Message() {
            public void print(a) {
                System.out.println("Hello World !"); }}); }public static void fun(Message msg) { msg.print(); }}Copy the code

In fact, the entire code, if fun(), would end up with just one output, but due to the integrity of Java’s development structure, more content has to be nested on this core statement. The above approach is too strict, hydrogen in JDK1.8 era introduced functional programming, can simplify the code.

** Use Lamda expressions

public interface Message {
    public void print(String str);
}

public class TestDemo {
    public static void main(String args[]) {
        // First define the variables that need to be received in this expression
        fun((s) -> System.out.println(s));
    }
    public static void fun(Message msg) {
        msg.print("Hello World !");  // Set the parameters}}Copy the code

The output

Hello World !
Copy the code

The anonymous inner class in the entire operation is just one line of output, so the Lamda expression can be used to accomplish the code requirements very easily. There are three forms of Lamda syntax:

  • (Parameter) -> Single line statement.
  • (Parameters) -> {multi-line statement}.
  • (Parameter) -> expression.

** Example: ** Write an expression

public interface Message {
    public int add(int x, int y);
}

public class TestDemo {
    public static void main(String args[]) {
        fun((s1, s2) -> s1 + s2);
    }
    public static void fun(Message msg) {
        System.out.println(msg.add(10.20)); }}Copy the code

The output

30
Copy the code

Method references

It has always been possible to find references only on objects, and the nature of object references is that different objects can operate on the same piece of content. A method reference is a method alias that defines a different name for a method. Method references are defined in Java8 in four forms:

  • Reference static method: class name :: static method name.
  • Methods that reference an object: Instantiate objects :: ordinary methods.
  • Reference to a specific type of method: specific class :: common method.
  • Reference constructor: class name :: new.
Reference static methods

In the String class there is a valueOf method: public static String valueOf(int x);

public interface Message<P.R> {
    public R zhuanhuan(P p);
}

public class TestDemo {
    public static void main(String args[]) {
        // That is, change the string.valueof () method to the zhuanhuan() method in the Message interface
        Message<Integer, String> msg = String :: valueOf();
        String str = msg.zhuanhuan(1000);
        Systemout.println(str.replaceAll("0"."9")); }}Copy the code

The output

1999
Copy the code
Plain method reference

** Example: ** Ordinary method references

public interface Message<R> {
    public R upper(a);
}

public class TestDemo {
    public static void main(String args[]) {
        Public String toUpperCase()
        // This method has no arguments, but returns a value, and can only be called if there is an instantiated object
        // The "hello" String is an instantiation of the String class, so you can call the toUpperCase() method directly
        // Assigns the toUpperCase() function to the Message interface
        Message<String> msg = "hello" :: toUpperCase;
        String str = msg.upper();  // equivalent to "hello".toupperCase ()"Systemout.println(str); }}Copy the code

The output

HELLO
Copy the code

Two code demonstrations showed that if you want to implement a reference to a function, you must have an interface, and most importantly, only one method in the interface (if multiple methods are present, you cannot reference them). So to ensure that there is only one method in the referenced interface, you need an annotated declaration @functionalInterface. Indicates that this is a functional interface and only one method can be defined.

A method that refers to a particular class

There is another form of method reference that requires the object support of a specific class. Normally, if you use “class :: method”, the reference must be a static method in the class, but this form can also refer to ordinary methods. For example, in the String class there is a method public int compareTo(String anotherString). CompareTo (string 2 object), which means you need to supply two arguments if you really want to reference this method.

** Example: ** references methods of a particular class

@FunctionalInterface
public interface Message<P> {
    public int compare(P p1, P p2);
}

public class TestDemo {
    public static void main(String args[]) {
        Message<String> msg = String :: compareTo;
        System.out.println(msg.compare("A"."B")); }}Copy the code

The output

- 1Copy the code

Instead of defining an object before a method reference, it can be understood as defining an object on a parameter.

Reference constructor

** Example: ** reference constructor

@FunctionalInterface
public interface Message<C> {
    public C create(String t, double p);
}

public class Book {
    private String title;
    private double price;
    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }
    @Override
    public String toString(a) {
        return "Title:" + this.title + ", price: + this.price + "。"; }}public class TestDemo {
    public static void main(String args[]) {
        Message<String> msg = Book :: new;  // Reference constructor
        // Create () is called, but this method references the construction of the Book class
        Book book = msg.create("Java development".20.2); System.out.println(book); }}Copy the code

The output

Title: Java Development, price: 20.2).Copy the code

Object references have different names, whereas method references require a functional interface and set parameters.

Built-in functional interfaces

Take a look at the new functional interface package provided in JDK1.8 and the four functional interfaces provided. The java.util.function package is available in JDK1.8, which provides the following four core interfaces: java.util.function

  • Functional interface: This interface needs to take a parameter and return a processing result.
public interface Function<T, R> {
    public R apply(T t);
}
Copy the code
  • Consumer interface: This interface is only responsible for receiving data (reference data does not need to be returned) and does not return processing results.
public interface Consumer<T> {
    public void accept(T t);
}
Copy the code
  • Suppliers: This interface does not receive parameters, but can return results.
public interface Suppliers<T> {
    public T get();
}
Copy the code
  • Predicate interfaces: used for Predicate operations.
public interface Predicate<T> {
    public boolean test(T t);
}
Copy the code

There are four functional interfaces in JDK1.8, so it is rarely up to users to define new functional interfaces.

The String class has a method: public Boolean startsWith(String STR).

public class TestDemo {
    public static void main(String args[]) {
        Function<String, Boolean> fun = "##hello" :: startsWith;
        System.out.println(fun.apply("# #")); }}Copy the code

The output

true
Copy the code

** Example: ** consumer interface

public class TestDemo {
    public static void main(String args[]) {
        Consumer<String> cons = System.out :: println;
        cons.accept("Hello World !"); }}Copy the code

The output

Hello World !
Copy the code

Public String toUpperCase() : toUpperCase();

public class TestDemo {
    public static void main(String args[]) {
        Supplier<String> sup = "hello":: toUpperCase; System.out.println(sup.get()); }}Copy the code

The output

HELLO
Copy the code

The ** assertion interface references the equalsIgnoreCase() method of the String class.

public class TestDemo {
    public static void main(String args[]) {
        Predicate<String> pre = "hello" :: equalsIgnoreCase;
        System.out.println(sup.test("hello")); }}Copy the code

The output

true
Copy the code

These interfaces contain all possible method references and are representative of functional interfaces, but there are many similar ones.

conclusion

  • The point of defining methods using default or static in interfaces is to avoid subclasses implementing the same code repeatedly. The use of interfaces should also be dominated by abstract methods.
  • Problem solved with Lamda expressions: Avoiding too many useless operations on anonymous inner classes.
  • The four methods refer to the basic form above, but do not use it now.
  • With these functional interfaces, you don’t need them anymore. These things are prepared for the final data stream.