JAVA基础之四-郎打表达式、函数式接口、流的简介
自从J8开始,对于开发JAVAEE应用的工程师而言,函数式接口会常常接触,某种程度上有点不可绕过。
这是因为在绝大部分企业中都会使用Spring来开发JAVAEE,而Spring在它的实现中越来越多地使用上函数式编程。
如果我们阅读它的源码,函数式编程是绕不过去的。
函数式编程有其好处,这个好处就是工程上的:让代码看起来简洁;如果你熟练一点,还是能够节省一些时间的。
就具体而言,函数式编程用起来和JS的郎打表达式差不多,不过后者更加随意的(因为不需要考虑性能和稳定性,相对后端而言)。
要了解java的函数式编程,需要掌握以下内容:
- 函数式接口
- 流api(即stream api)
- 函数式编程优缺点和适用的业务场景
- JAVA中函数式编程的未来瞻望
需要特别注意的是,在java函数式编程中,几个重点类/接口所在的包:
1.java.util.function
2.java.util.stream
而FunctionalInterface接口则位于java的核心的核心:java.lang,获得了类似Integer,String等基础类的核心地位。
看起来JCP似乎要给予FunctionalInterface一个重要的位置和期许。
一、函数式接口
1.1、定义
新增的核心类型-函数接口注解
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FunctionalInterface {}
函数式接口的实现是java自行实现的。和我们在spring中定义各种注解不太一样。
看这个注解,知道三个重要信息:
Documented -- 会在javaDoc之类工具生成的文档中展示
Retention- 只有运行时才会生效
Target- 只能用于对象(具体是接口)
如前, FunctionalInterface位于java.lang下,而不是位于java.lang.annotation。
函数式接口定义
一种特有的接口,必须具备两个特点:
1.必须在接口上添加@FunctionalInterface注解,表明这是一个函数接口
2.在接口体内只能定义一个public abstract类型的方法。
@FunctionalInterface public interface Isort { public int add(int a,int b); }
3.虽然只能定义一个公共抽象方法,但其实还可以定义其它乱七八糟的东西,但只有以下是允许的:only public, private, abstract, default, static and strictfp are permitted
换言之,可以定义私有方法,默认方法等,但只要保证一个原则即可:只能有一个公共的抽象方法
package study.base.oop.interfaces.functional; import java.util.Random; @FunctionalInterface public interface Isort { /** * 1.允许定义公共静态属性 * 2.允许默认方法 * 3.允许私有方法(私有,静态私有) */ public static int SORT_TYPE_ASC=1; public static int SORT_TYPE_DESC=2; //私有静态 private static int rand() { return (new Random()).nextInt(100); } //私有方法 private void testPrivate() { System.out.printf("生车一个随机数%d\n", rand()); } //默认方法 default void doSomething(int a,int b) { testPrivate(); System.out.printf("两个参数分别是%d,%d",a,b); } //公共抽象方法 -- 这是函数式接口对外暴露的唯一方法 public int add(int a,int b); }
验证代码见后端有关章节。
java自身从J8之后,创建了一个很重要的类型
@FunctionalInterface public interface Function<T, R> { }
并有大量基于这个接口的实现,某种形式上,Function类似于Object在类中地位。
除了Funciton,还推出了相关一堆的类型,以便支持流式API,例如:
Predicate,Supplier,Consumer...
概念有点小多,需要专门另开文章阐述。
1.2、简单实现
java目前提供了5种方式,用于实现函数式接口:
1.传统类
2.朗打表达式
3.匿名函数
4.方法引用
5.构造函数
其中2~5是重点,目的都是为了节省编码+实现流式API。
为了演示这几种实现方式,我写了一个相对完整的例子,具体如下(为了节省篇幅,放在一起,不再列出包等信息),其中最重要的函数式接口Isort 见前文。
//实现类 public class Sort { public int add(int a, int b) { int total= a+b; System.out.println("虽然不是函数式实现,但是方法同约定方法一样的结果:"+total); return total; } } //用于演示基于构造函数引用 @FunctionalInterface public interface IFace { public Face show(int a,int b); } public class Face { int a; int b; public Face(int a,int b) { this.a=a; this.b=b; } public void write() { System.out.println(a+b); } }
测试代码:
package study.base.oop.interfaces.functional.std.impl;
import java.util.function.Function;
import study.base.oop.interfaces.functional.std.Face;
import study.base.oop.interfaces.functional.std.IFace;
import study.base.oop.interfaces.functional.std.Isort;
import study.base.oop.interfaces.functional.std.Sort;
/**
* 本类主要演示了函数式接口的几种实现方式:
* </br>
* </br> 1.使用实现类 - 最传统的
* </br> 2.使用Lambda表达式 - 还是比较方便的
* </br> 3.使用匿名类 - 和郎打差不多
* </br> 4.方法引用 - 应用另外一个同形方法(多式对实例)
* </br> 5.构造器引用 - 应用另外一个同形构造方法
* </br> 6.静态方法引用 - 应用另外一个同形静态方法
* @author lzf
*/
public class StudentSortImpl implements Isort {
@Override
public int add(int a, int b) {
int total = a + b;
System.out.println(total);
this.doSomething(a,b);
return total;
}
public static void main(String[] args) {
// 1.0 函数式接口的传统实现-类实现
System.out.println("1.函数式接口的实现方式一:实现类");
Isort sort = new StudentSortImpl();
sort.add(10, 20);
Function f;
Integer.sum(10, 20);
// 函数式接口的实现二-朗打方式
System.out.println("2.函数式接口的实现方式一:朗打表达式");
// 2.1 有返回的情况下,注意不要return语句,只能用于单个语句的
// 如果只有一个参数,可以省掉->前的小括弧
// 如果有返回值,某种情况下,也可以省略掉后面的花括弧{}
// 有 return的时候
// a->a*10
// (a)->{return a*10} 要花括弧就需要加return
// (a,b)->a+b
// (a,b)->{return a+b;}
Isort sort2 = (a, b) -> a + b;
Isort sort3 = (a, b) -> {
return a * 10 + b;
};
// 2.2 有没有多条语句都可以使用 ->{}的方式
Isort sort4 = (a, b) -> {
a += 10;
return a + b;
};
int a=10;
int b=45;
int total=sort2.add(a, b)+sort3.add(a, b)+sort4.add(a, b);
System.out.println("总数="+total);
// 3 使用 new+匿名函数的方式来实现
System.out.println("3.函数式接口的实现方式一:匿名类");
Isort sort5 = new Isort() {
@Override
public int add(int a, int b) {
int total = a * a + b;
System.out.println(total);
return total;
}
};
sort5.add(8, 2);
// 4.0 基于方法引用-利用已有的方法,该方法必须结构同接口的方式一致