前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Java】23 函数式编程

【Java】23 函数式编程

作者头像
Demo_Null
发布2020-09-28 11:10:26
5090
发布2020-09-28 11:10:26
举报
文章被收录于专栏:Java 学习Java 学习Java 学习

函数式接口(Functional Interface)是 JDK 1.8 对一类特殊类型的接口的称呼。 这类接口有且仅有一个抽象方法,并且这类接口使用了 @FunctionalInterface 进行注解。

1.1 Lambda 表达式

1.1.1 冗余的代码

  当需要启动一个线程去完成任务时,通常会通过java.lang.Runnable接口来定义任务内容,并使用java.lang.Thread类来启动该线程。“一切皆对象”作为指导思想,这种做法没毛病:首先创建一个Runnable接口的匿名内部类对象来指定任务内容,再将其交给一个线程来启动。

public class DemoRunnable {
	public static void main(String[] args) {
    	// 匿名内部类
		new Thread(new Runnable() {
			@Override
			public void run() { 
				System.out.println("多线程任务执行!");
			}
		}).start(); 
	}
}

我认为目前为止,上述代码已经是极简形式,对上述代码进行分析:

  ♞ Thread类需要Runnable接口作为参数,其中的抽象run方法是用来指定线程任务内容的核心;

  ♞ 为了指定run的方法体,需要Runnable接口的实现类;

  ♞ 此处为了省去定义一个RunnableImpl实现类的麻烦,使用匿名内部类;

  ♞ 重写run方法,所以方法名称、方法参数、方法返回值再写一遍;

似乎只有方法体才是关键,我们真正希望做的事情是:将run方法体内的代码传递给Thread类知晓。

  在生活中,当我们需要从武汉到深圳时,可以选择高铁、汽车、骑行甚至是徒步。我们的真正目的是到达深圳,而如何才能到达深圳的形式并不重要,比高铁更好的方式——飞机。那么上述代码有没有更简洁的形式? JDK 1.8 中,加入了Lambda表达式的重量级新特性,为我们打开了新世界的大门。

1.1.2 Lambda 更优写法

public class DemoLambdaRunnable {
	public static void main(String[] args) {
		new Thread(() -> System.out.println("多线程任务执行!")).start();
	}
}

上述代码和 1.1.1 的执行效果是完全一样的,可以在 JDK 1.8 或更高的编译级别下通过。从代码中可以看出:省略了我们不需要的东西,以一种极简的形式执行了线程任务。

1.1.3 Lambda 入门

标准格式

  Lambda 省去面向对象的条条框框,格式由 3 部分组成: 一些参数、一个箭头、一段代码,即:(参数类型 参数名称) -> { 代码语句 }。小括号内的语法与传统方法参数列表一致,无参数则留空;多个参数则用逗号分隔。 ->是新引入的语法格式,代表指向动作。大括号内的语法与传统方法体要求基本一致。

示例

首先定义一个接口 Add,提供抽象方法 add( )

public interface Add {
    public abstract int add(int a, int b);
}

然后定义一个方法 show( ),调用抽象方法 add( ) , 最后将使用 λ 表达式构建的 Add 接口子类对象传递给 show 方法。

public class Demo {
    public static void main(String[] args) {
        show(2, 3, (int a, int b) -> { return a + b;});
    }

    public static void show(int a, int b, Add add) {
        System.out.println(add.add(a, b));
    }
}

补充:  使用 λ 表达式必须具有接口,且要求接口中有且仅有一个抽象方法,且可以根据上下文推导相关信息。  λ 表达式小括号内参数的类型可以省略;如果小括号内有且仅有一个参数,则小括号可以省略;如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。


1.2 函数式接口

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

1.2.1 自定义函数式接口

/* 
	@FunctionalInterface
	一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。
	需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来没有区别。
*/
@FunctionalInterface
public interface MyFunctionInterface {
	// 有且仅有一个抽象方法的接口
    public abstract int myMethod();
}

1.2.2 常用函数式接口

【Java】24 常用函数式接口


1.3 函数式编程

1.3.1 Lambda 的延迟执行

public class Demo {
    private static void show(int i, String msg) {
        if (i == 1) {
            System.out.println(msg);
        }
    }

    public static void main(String[] args) {
        String msgA = "你好";
        String msgB = "Hello";
        String msgC = "Java";
        
        show(2, msgA + msgB + msgC);
    }
}

  在调用 show( ) 方法时,无论 show( ) 方法方法体是什么,都会将 msgA + msgB + msgC 拼接为一个字符串传递过去,然而参数可能并不满足 show( ) 方法体执行的条件,拼接好的字符串就成了垃圾,此时就造成了性能浪费。Lambda 表达式完美的解决了这一问题,即:延迟执行,也可以认为不使用,不执行。

  如图所示,在不符合条件的情况下,Lambda 表达式将不会执行,从而达到节省性能的效果。实际上使用内部类也可以达到同样的效果,只是将代码操作延迟到了另外一个对象当中通过调用方法来完成。而是否调用其所在方法是在条件判断之后才执行的。

1.3.2 Lambda 作为参数和返回值

  Java 中的 Lambda 表达式可以被当作是匿名内部类的替代品。如果方法的参数是一个函数式接口类型,那么就可以使用 Lambda 表达式进行替代。使用 Lambda 表达式作为方法参数,其实就是使用函数式接口作为方法参数。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.1 Lambda 表达式
    • 1.1.1 冗余的代码
      • 1.1.2 Lambda 更优写法
        • 1.1.3 Lambda 入门
          • 标准格式
          • 示例
      • 1.2 函数式接口
        • 1.2.1 自定义函数式接口
          • 1.2.2 常用函数式接口
          • 1.3 函数式编程
            • 1.3.1 Lambda 的延迟执行
              • 1.3.2 Lambda 作为参数和返回值
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档