Java8 functional interface, lambda expression, interface default method

Functional interface:

When there is only one abstract method in the interface, it is a functional interface. You can use the annotation (@FunctionalInterface) to force the interface to be a functional interface, that is, there can only be one abstract method.

E.g:

package com.simple.lambdajava;

/**
 * Created by zhubo on 2018/4/14.
 * 默认是函数式接口
 */
public interface Interface1 {
    void method1();
}

The above interface has only one abstract method, then the default is a functional interface.

interface Integerface2 {  
     void test();  
     void test2();  
}  

The interface has two abstract methods, not a functional interface

@FunctionalInterface  
interface Integerface2 {  
      
}  

The above compilation will report an error, because the @FunctionalInterface annotation declares that the interface is a functional interface and must have only one abstract method.

@FunctionalInterface
public interface Interface1 {
    void method1();
}

Lambda expressions can only be used against functional interfaces.

Static method in interface:

Since java8, there can be static methods in the interface, which can be modified with static, but the modifier of the static method in the interface can only be public, and the default is public.

package com.simple.lambdajava;

/**
 * Created by zhubo on 2018/4/14.
 * 接口里的静态方法
 */
public interface TestStaticMethod {

    static void test1() {
        System.out.println("接口里的静态方法!");
    }
}

Use the interface class name to call a static method:

/**
 * Created by zhubo on 2018/4/14.
 */
public class Test {
    public static void main(String[] args) {
        TestStaticMethod.test1();
    }
}

 

/**
 * Created by zhubo on 2018/4/14.
 * 接口里的静态方法
 * 也是函数式接口
 */
@FunctionalInterface
public interface TestStaticMethod {
    // 这是一个抽象方法
    void test();
    // 静态方法,不是抽象方法
    static void test1() {
        System.out.println("接口里的静态方法!");
    }
}

The above code will not report an error, you can see that the interface is still a functional interface

Default method of interface:

In java8, in addition to writing static methods in interfaces, you can also write non-static methods, but they must be modified with default, and they can only be public, and the default is also public.

//非静态default方法  
interface TestDefaultMethod{  
     default void test() {  
           System.out.println("这个是接口里的default方法test");  
     }  
     public default void test1() {  
           System.out.println("这个是接口里的default方法test1");  
     }  
     //编译报错  
//   private default void test2() {  
//         System.out.println("这个是接口里的default方法");  
//   }  
}  

Since it is not a static method, it must be instantiated before it can be called.

public class Test {  
     public static void main(String[] args) {  
  
           //使用匿名内部类初始化实例  
           TestDefaultMethod tx = new TestDefaultMethod() {  
           };  
           tx.test();  
           tx.test1();  
     }  
}  

Default methods can be inherited. However, it should be noted that if the default methods in the two interfaces are inherited, they must be rewritten.

interface A {  
     default void test() {  
           System.out.println("接口A的默认方法");  
     }  
}  
interface B {  
     default void test() {  
           System.out.println("接口B的默认方法");  
     }  
}  
interface C extends A,B {  
  
}  

Here, an error will be reported at interface c, because the compiler does not know whether you are inheriting the default method of A or the default method of B. It can be rewritten as follows, using super to explicitly call the method of which interface:

interface C extends A,B {  
  
     @Override  
     default void test() {  
           A.super.test();  
     }  
  
}  

test:

public class Test {  
     public static void main(String[] args) {  
           C c = new C() {  
           };  
           c.test();  
     }  
}  

The same is true for a class inheriting two interfaces with the same default methods, which must be overridden.

The following code compiles with an error

class D implements A,B {  
     void test() {  
  
     }  
}  

Because the test method of A or B is the default method and the modifier is public, the modifier to override the method must be equal to or greater than it, and public is already the largest access modifier, so the modifier here must be public

class D implements A,B {  
     @Override  
     public void test() {  
           A.super.test();  
     }  
}  
public static void main(String[] args) {  
  
      D d = new D();  
      d.test();  
}  

Note: The default method is not an abstract method, so the following interface is still a functional interface.

@FunctionalInterface  
interface A {  
     default void test() {  
           System.out.println("接口A的默认方法");  
     }  
     void test1();  
}  

Default methods can be used in interfaces to implement abstract methods of the parent interface. Such as:

interface C extends A,B {  
  
     @Override  
     default void test() {  
           A.super.test();  
     }  
     default void test1() {  
           System.out.println("在子接口实现父接口的抽象方法");  
     }  
  
}  
C c = new C() {  
 };  
c.test1();  

Can be overridden when actually using anonymous function calls:

C c = new C() {  
     @Override  
     public void test1() {  
          System.out.println("调用时重写");  
     }  
};  
c.test1();  

 

The default method of the parent interface can be overridden in the child interface to make it an abstract method.

interface E {  
     default void test() {  
           System.out.println("接口E的默认方法");  
     }  
}  
interface F extends E {  
    void test();  
}  

The following main method will not report an error if it is written like this

E e = new E(){  
  
};  
e.test(); 

But if so:

F f = new F(){  
  
};  
f.test();

Then a compilation error will be reported, requiring you to implement the test() method:

Can be changed to:

public static void main(String[] args) {  
  
      F f = new F(){  
           @Override  
           public void test() {  
                System.out.println("F接口实现");  
           }  
      };  
      f.test();  
}  

 

Lambda expressions

Can be thought of as a special anonymous inner class

lambdas can only be used with functional interfaces.

lambda syntax:

     ([parameter list, without data type]) -> {

     // execute statement

     [return..;]

}

Notice:

1. If the parameter list is empty, just keep ()

2. If there is no return value. Just write the execution statement in {}

3. If the abstract method of the interface has only one formal parameter, () can be omitted, and only the name of the parameter is required.

4. If the execution statement has only one line, you can omit {}, but if there is a return value, the situation is special.

5. If the method of the functional interface has a return value, the return value must be given. If the execution statement has only one sentence, it can also be abbreviated, that is, the curly brackets, return and the final ; are omitted.

6. The data type of the formal parameter list will be automatically inferred, only the parameter name is required.

public class TestLambda {  
     public static void main(String[] args) {  
           TestLanmdaInterface1 t1 = new TestLanmdaInterface1() {  
                @Override  
                public void test() {  
                     System.out.println("使用匿名内部类");  
  
                }  
           };  
           //与上面的匿名内部类执行效果一样  
           //右边的类型会自动根据左边的类型进行判断  
           TestLanmdaInterface1 t2 = () -> {  
                System.out.println("使用lanbda");  
           };  
           t1.test();  
           t2.test();  
  
           //如果执行语句只有一行,可以省略大括号  
           TestLanmdaInterface1 t3 = () -> System.out.println("省略执行语句大括号,使用lanbda");  
           t3.test();  
  
           TestLanmdaInterface2 t4 = (s) -> System.out.println("使用lanbda表达式,带1个参数,参数为:"+s);  
           t4.test("字符串参数1");  
  
           TestLanmdaInterface2 t5 = s -> System.out.println("使用lanbda表达式,只带1个参数,可省略参数的圆括号,参数为:"+s);  
           t5.test("字符串参数2");  
  
           TestLanmdaInterface3 t6 = (s,i) -> System.out.println("使用lanbda表达式,带两个参数,不可以省略圆括号,参数为:"+s+"  "+ i);  
           t6.test("字符串参数3",50);  
     }  
}  
  
@FunctionalInterface  
interface TestLanmdaInterface1 {  
     //不带参数的抽象方法  
     void test();  
}  
@FunctionalInterface  
interface TestLanmdaInterface2 {  
     //带参数的抽象方法  
     void test(String str);  
}  
@FunctionalInterface  
interface TestLanmdaInterface3 {  
     //带多个参数的抽象方法  
     void test(String str,int num);  
}  

 

package com.Howard.test12;  
  
public class CloseDoor {  
     public void doClose(Closeable c) {  
           System.out.println(c);  
           c.close();  
     }  
  
     public static void main(String[] args) {  
           CloseDoor cd = new CloseDoor();  
           cd.doClose(new Closeable() {  
                @Override  
                public void close() {  
                     System.out.println("使用匿名内部类实现");  
  
                }  
           });  
  
           cd.doClose( () -> System.out.println("使用lambda表达式实现"));  
     }  
}  
@FunctionalInterface  
interface Closeable {  
     void close();  
}  

As you can see, lambda expressions and anonymous inner classes are not exactly the same

Looking at the generated class file, we can see that the lambda expression does not generate additional .class files, while the anonymous inner class generates CloseDoor$1.class

Like anonymous inner classes, if you access local variables, the local variables must be final. If final is not added, it will be added automatically.

E.g:

public class TestLambdaReturn {  
     void re(LambdaReturn lr) {  
           int i = lr.test();  
           System.out.println("lambda表达式返回值是:"+i);  
     }  
  
     public static void main(String[] args) {  
           int i = 1000;  
           tlr.re( () -> i);  
             
     }  
}  
interface LambdaReturn {  
     int test();  
}  
            
如果只是上面那样写,编译不会报错,但是如果改为:  
     public static void main(String[] args) {  
           int i = 1000;  
           tlr.re( () -> i); //报错  
           i = 10;  
     } 

Using i as a non-final variable will result in an error on the line of the lambda expression.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324431687&siteId=291194637