长亭百川云 - 文章详情

接口和Lambda表达式

Delphi研习社

42

2024-07-13

Java 接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)

引自百度百科

在 JDK1.8 以前接口中是不允许存在具体的方法实现的,也就是说全部都是抽象方法。所以我们可以把接口看作是更为彻底的抽象类

接口更多的时候是一种公共的规范标准,只有符合标准才可以通用,其定义和使用如下

public interface UserDao {  
  
}  
  
public class UserDaoImpl implements UserDao{  
  
}  

接口和其成员的特点

  • 接口本身不能实例化,同时要求其实现类必须实现接口中的抽象方法。一个类可以同时实现多个接口

  • 成员变量默认使用的修饰符为 public static final 也就是常量

  • 成员方法默认使用的修饰符为 public abstract

函数式接口

函数式接口在 Java 中是指:有且仅有一个抽象方法的接口。

函数式接口,即适用于函数式编程场景的接口。而 Java 中的函数式编程体现就是 Lambda,所以函数式接口就是可以适用于 Lambda 使用的接口。只有确保接口中有且仅有一个抽象方法,Java 中的 Lambda 才能顺利地进行推导。

 修饰符 interface 接口名称 {  
    public abstract 返回值类型 方法名称(可选参数信息);  
    // 其他非抽象方法内容  
}

由于接口当中抽象方法的 public abstract 是可以省略的,所以定义一个函数式接口很简单

public interface MyFunctionalInterface {  
    void myMethod();  
}

@FunctionalInterface

与 @Override 注解的作用类似,Java 8 中专门为函数式接口引入了一个新的注解: @FunctionalInterface 。该注解可用于一个接口的定义上:

@FunctionalInterface  
public interface MyFunctionalInterface {  
    void myMethod();  
}  

一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。

Lambda 表达式

Lambda 的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:

  • 使用 Lambda 必须具有接口,且要求 接口中有且仅有一个抽象方法

  • 使用 Lambda 必须具有 上下文推断 也就是方法的参数或局部变量类型必须为 Lambda 对应的接口类型,才能使用 Lambda 作为该接口的实例。

Lambda 表达式的 标准格式 :(参数类型 参数名称) -> { 代码语句 }

@FunctionalInterface  
public interface MyFunctionalInterface {  
  
    void myMethod();  
}  
  
public class Demo1 {  
  
    public static void demo1(MyFunctionalInterface functionalInterface) {  
        functionalInterface.myMethod();  
    }  
    public static void main(String[] args) {  
        demo1(() -> {  
            System.out.println("HelloWorld");  
        });  
    }  
}  

在一些特定的情况下 lambda 表示可以进行简写(即省略某些声明),其简写规则如下:

  1. 小括号内参数的类型可以省略;

  2. 如果小括号内 有且仅有一个参 ,则小括号可以省略;

  3. 如果大括号内 有且仅有一个语句 ,则无论是否有返回值,都可以省略大括号、return 关键字及语句分号。

案例代码

@FunctionalInterface  
public interface UserDao {  
  
    void add(String uname);  
}  
  
  
public class Demo2 {  
  
    public static void demo1(UserDao userDao){  
  
        userDao.add("小黑");  
    }  
  
    public static void main(String[] args) {  
        //->后面的代码就是 add 方法的具体实现  
        demo1(uname-> System.out.println(uname));  
    }  
}  

很明显,因为 Lambda 表达式需要借助于类型推导(也可以叫上下文推导),所以它只适用于接口中只有一个抽象方法的情况(即函数式表达式)。它无法完全代替内部类和匿名内部类,最多算是匿名内部在特定条件下的一种简写方式

方法引用

方法引用应该是在 JDK1.8 新增的概念了,它采用的是操作符是::双冒号运算操作符是类方法的句柄,Lambda 表达式的一种简写,这种简写的学名叫 eta-conversion 或者叫η-conversion。

感觉有点儿像其他语言中接口的委托实现

方法引用的格式为:<ClassName | instance>::<MethodName>

至于为什么要使用这个方法引用,我们来看一段代码,代码仅为演示使用没有实际的业务意义

@FunctionalInterface  
public interface UserDao {  
  
    void add(String uname);  
}  
  
  
public class Demo {  
  
    public static void testQuote(UserDao userDao){  
        userDao.add("小明");  
    }  
    public static void main(String[] args) {  
  
        testQuote(uname->{  
            // 此处为新增用户的代码  
  
            // 数据校验  
  
            // 事务处理(新增用户可能用不到事务,这里仅仅是举例)  
  
            // 数据联动处理...... 以下省略  
        });  
    }  
}  

代码解析

在上面的代码片段中我们可以明确的看到 Lambda 表达式内有一大堆的代码,无论从阅读性还是从代码的简洁性上来讲都非常差

我们变成方法引用的方式再实现一遍

public class Demo3 {  
  
    public static void testQuote(UserDao userDao){  
        userDao.add("小明");  
    }  
    public static void quoteAdd(String uname){  
        // 此处为新增用户的代码  
  
        // 数据校验  
  
        // 事务处理(新增用户可能用不到事务,这里仅仅是举例)  
  
        // 数据联动处理...... 以下省略  
    }  
    public static void main(String[] args) {  
  
        testQuote(Demo3::quoteAdd);  
    }  
}  

代码解析

  • 效果很明显,只是将实现的方法单独的抽离出去了

  • main 方法中引用 quoteAdd 方法的采用的是静态方法的处理

静态方法和实例方法的引用方式

@FunctionalInterface  
public interface UserDao {  
  
    void add(String uname);  
}  
  
// 用于演示实例方法引用  
public class Quote {  
    public void addImpl(String uname) {  
        System.out.println(uname);  
    }  
}  
  
// 用于演示静态方法引用  
public class StaticQuote {  
    public static void addImpl(String uname) {  
        System.out.println(uname);  
    }  
}  
  
public class Demo2 {  
  
    public static void demo1(UserDao userDao) {  
  
        userDao.add("小黑");  
    }  
  
    public static void main(String[] args) {  
        // 具体引用代码  
        demo1(new Quote()::addImpl);  
  
        demo1(StaticQuote::addImpl);  
    }  
}  

下面的代码演示了由匿名内部类 -->Lambda 表达式 -->方法引用的各个方式

// 函数式接口  
@FunctionalInterface  
public interface MyFunctionalInterface {  
  
    void myMethod();  
}  
  
public class Demo1 {  
  
    public static void demo1(MyFunctionalInterface functionalInterface) {  
        functionalInterface.myMethod();  
    }  
    public static void main(String[] args) {  
  
        demo1(new MyFunctionalInterface() {  
            @Override  
            public void myMethod() {  
                System.out.println("匿名内部类");  
            }  
        });  
  
        demo1(()->{  
            System.out.println("Lambda 表达式");  
        });  
  
  
        demo1(Demo1::myMethod);  
  
    }  
  
    private static void myMethod() {  
        System.out.println("方法引用");  
    }  
}
相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2