跟着老侯玩编程 跟着老侯玩编程
首页
  • 基础语法
  • 网络编程
  • 设计模式
  • 基础篇
  • 进阶篇
  • 框架篇
  • Redis
  • Alibaba
  • 课程目录
  • 码农宝典
留言
首页
  • 基础语法
  • 网络编程
  • 设计模式
  • 基础篇
  • 进阶篇
  • 框架篇
  • Redis
  • Alibaba
  • 课程目录
  • 码农宝典
留言
  • 基础篇

    • 聊聊环境变量
    • 永不过时的HelloWorld
    • 标识符
    • 数据类型
    • 运算符
    • 语句
    • 数组
    • 方法详解
    • 类和对象
    • 类的成员
    • 类的继承
    • 类的形式
    • 封装和多态
    • 接口和Lambda表达式
      • 函数式接口
        • @FunctionalInterface
      • Lambda 表达式
      • 方法引用
    • 泛型编程
    • 常用API之函数式接口
    • 常用API
    • 异常机制
    • 多线程
    • 常用API之File类
    • IO流
    • 集合
    • 常用API之Stream流
    • 网络编程
    • 枚举
    • 注解和反射
  • 进阶篇

    • MySQL基础
    • 数据库-JDBC
    • HTML基础
    • CSS基础
    • JavaScript-基础
    • 服务器-Servlet
    • 服务器-Servlet3
    • 动态网页-JSP
    • Ajax
    • 前端项目工程化
    • ECMA2015
    • 模块化规范
  • 框架篇

    • 工具-Maven
    • 框架-MyBatis
    • 框架-Spring
    • 框架-SpringMVC
    • 工具-SpringBoot
    • 工具-Nginx
  • Java
  • 基础篇
舞动的代码
2022-05-17
目录

接口和Lambda表达式

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

引自百度百科

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

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


public interface UserDao {

}

public class UserDaoImpl implements UserDao{

}

1
2
3
4
5
6
7
8
9

接口和其成员的特点

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

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

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

# 函数式接口

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

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


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

1
2
3
4
5
6

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


public interface MyFunctionalInterface {
	void myMethod();
}

1
2
3
4
5

# @FunctionalInterface

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


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

1
2
3
4
5
6

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

# 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");
        });
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

在一些特定的情况下 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));
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

很明显,因为 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->{
            // 此处为新增用户的代码

            // 数据校验

            // 事务处理(新增用户可能用不到事务,这里仅仅是举例)

            // 数据联动处理...... 以下省略
        });
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

代码解析

在上面的代码片段中我们可以明确的看到 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);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

代码解析

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

  • 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);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

下面的代码演示了由匿名内部类 -->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("方法引用");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
封装和多态
泛型编程

← 封装和多态 泛型编程→

Theme by Vdoing | Copyright © 2013-2023 冀ICP备16006233号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×