java8新特性之函数式接口

虽然刚发布了java11版本,但是对于java8中新的特性我们仍需要掌握,毕竟大部分开发都是用的jdk8,以及java11中仍然保留着这些特性,接下来我就网上查找资料做了一下总结,如果哪里说的不对头,还请各位大佬指出来,我会及时更正。

1.函数式接口定义:

那么函数接口到底是什么呢?是个接口,只包含一个抽象方法,则该接口称之为函数式接口,我们可以在任意函数式接口上使用 @FunctionalInterface 检查它是否是一个函数式接口,也可不添加该注解,如:

public interface Test {

    default void defaultMethod(){
        System.out.println("Test defalut 方法");
    }

    int sub(int a,int b);

    static void staticMethod() {
        System.out.println("Test static 方法");
    }
}

2.特点

函数式接口里是可以包含默认方法、静态方法,他们不是抽象方法;也可以包含Java.lang.Object里的public方法,因为任何一个类都继承Object类,包含了来自java.lang.Object里对这些抽象方法的实现,也不属于抽象方法;函数式接口里允许子接口继承多个父接口,但每个父接口中都只能存在一个抽象方法,且必须的相同的抽象方法,一般和Lamdba表达式一起用,总结下分为两点:

函数式接口是仅制定一个抽象方法的接口,

可以包含一个或多个静态或默认方法.

3.该类接口中的static方法不能被继承,也不能被实现类调用,只能被自身调用

定义一个函数式接口:

public interface DefalutTest {
    static int a =5;
    default void defaultMethod(){
        System.out.println("DefalutTest defalut 方法");
    }

    int sub(int a,int b);

    static void staticMethod() {
        System.out.println("DefalutTest static 方法");
    }
}

实现该接口:

public class DefaultTestImpl implements DefalutTest{

    @Override
    public int sub(int a, int b) {
        // TODO Auto-generated method stub
        return a-b;
    }

}

测试:

public static void main(String[] args) {
        DefaultTestImpl dt = new DefaultTestImpl();
        dt.defaultMethod(); //接口中的默认方法可以通过实现类对象调用
        DefalutTest.staticMethod();//接口中静态不能通过实现类对象调用,只能通过接口本身调用
    }

发现实现类对象能够调用接口的默认方法,不能调用静态方法。但是静态方法可通过接口本身调用。

继承也是这种情况,就不细说了。所以得出结论:

接口里的静态方法,即static修饰的有方法体的方法不会被继承或者实现,但是静态变量会被继承 

4.该类接口中的默认方法

①default方法可以被子接口继承亦可被其实现类所调用

准备一个子接口继承DefalutTest接口

public interface SubTest extends DefalutTest{

}

准备一个子接口的实现类

public class SubTestImp implements SubTest{

    @Override
    public int sub(int a, int b) {
        // TODO Auto-generated method stub
        return a-b;
    }

}

现在我们创建一个子接口实现类对象,并调用对象中的default方法:

public class Main {

    public static void main(String[] args) {
        SubTestImp st = new SubTestImp();
        stl.defaultMethod();

    }
}

执行结果:
DefalutTest defalut 方法

②default方法被继承时,可以被子接口覆写

现在我们在子接口中重写default方法,在进行调用:

public interface SubTest extends DefalutTest{

    default void defaultMethod(){
        System.out.println("SubTest defalut 方法");
    }
}

执行结果:SubTest defalut 方法

③如果一个类实现了多个接口,且这些接口中无继承关系,这些接口中若有相同的(同名,同参数)的default方法,则接口实现类会报错,接口实现类必须通过特殊语法指定该实现类要实现那个接口的default方法 

我们去除接口间的继承关系,并使得SubTestImp同时实现父接口和子接口,我们知道此时父接口和子接口中存在同名同参数的default方法,这会怎么样? 
结果实现类报错,实现类要求必须指定他要实现那个接口中的default方法:
 

解决方法:使用特殊语法:<接口>.super.<方法名>([参数]) 

public class SubTestImp implements SubTest,DefalutTest{

    @Override
    public int sub(int a, int b) {
        // TODO Auto-generated method stub
        return a-b;
    }

    @Override
    public void defaultMethod() {
        // TODO Auto-generated method stub
        DefalutTest.super.defaultMethod();
    }

}

 

5.Java8内置函数式接口

四大核心函数式接口

函数式接口 方法 参数类型 返回类型 作用
Consumer<T> 消费型接口 void accept(T t) T void 对T类型的参数进行操作
Supplier<T> 供给型接口 T get() T 操作数据,返回T类型的结果
Function<T, R> 函数型接口 R apply(T t) T R 对T类型参数进行操作,并返回R类型的结果
Predicate<T> 断定型接口 boolean test(T t) T boolean 确定T类型参数是否满足某约束,并返回boolean值
//Consumer<T> 消费型接口
  @Test
  public void test1(){
    Consumer<String> c = (x) -> System.out.println("hello:"+x+"!");
    c.accept("Java");
  }
  // Supplier<T> 供给型接口
  @Test
  public void test2(){
    Supplier<String> s = () -> "hello,beautiful girl";
    String str = s.get();
    System.out.println(str);
  }
  //Function<T,R> 函数性接口
  @Test
  public void test3(){
    Function<String, Integer> f= (x) -> x.length();
    Integer len = f.apply("hello");
    System.out.println(len);
  }
  //Predicate<T> 断言型接口
  @Test
  public void test4(){
    Predicate<String> p = (x) -> x.length()>5;
    boolean b = p.test("hello Java");
    System.out.println(b);
  }