Function源码解析与实践
source link: https://blog.51cto.com/u_15714439/5894627
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
作者:陈昌浩
if…else… 在代码中经常使用,听说可以通过 Java 8 的 Function 接口来消灭 if…else…!Function 接口是什么?如果通过 Function 接口接口消灭 if…else… 呢?让我们一起来探索一下吧。
2 Function 接口
Function 接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,Function 接口可以被隐式转换为 lambda 表达式。可以通过 FunctionalInterface 注解来校验 Function 接口的正确性。Java 8 允许在接口中加入具体方法。接口中的具体方法有两种,default 方法和 static 方法。
interface TestFunctionService
{
void addHttp(String url);
}
那么就可以使用 Lambda 表达式来表示该接口的一个实现。
2.1 FunctionalInterface
2.1.1 源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
2.1.2 说明
上图是 FunctionalInterface 的注解说明。通过上面的注解说明,可以知道 FunctionalInterface 是一个注解,用来说明一个接口是函数式接口。 函数式接口只有一个抽象方法。 可以有默认方法,因为默认方法有一个实现,所以不是抽象的。函数接口的实例可以用 lambda 表达式、方法引用或构造函数引用创建。
FunctionalInterface 会校验接口是否满足函数式接口:
- 类型必须是接口类型,不能是注释类型、枚举或类。
- 只能有一个抽象方法。
- 可以有多个默认方法和静态方法。
- 可以显示覆盖 java.lang.Object 中的抽象方法。
编译器会将满足函数式接口定义的任何接口视为函数式接口,而不管该接口声明中是否使用 FunctionalInterface 注解。
3 Function 接口主要分类
Function 接口主要分类:
- Function:Function 函数的表现形式为接收一个参数,并返回一个值。
- Supplier:Supplier 的表现形式为不接受参数、只返回数据。
- Consumer:Consumer 接收一个参数,没有返回值。
- Runnable:Runnable 的表现形式为即没有参数也没有返回值。
3.1 Function
Function 函数的表现形式为接收一个参数,并返回一个值。
3.1.1 源码
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
3.1.2 方法说明
- apply:抽象方法。将此函数应用于给定的参数。参数 t 通过具体的实现返回 R。
- compose:default 方法。返回一个复合函数,首先执行 fefore 函数应用于输入,然后将该函数应用于结果。如果任意一个函数的求值引发异常,则将其传递给组合函数的调用者。
- andThen:default 方法。返回一个复合函数,该复合函数首先对其应用此函数它的输入,然后对结果应用 after 函数。如果任意一个函数的求值引发异常,则将其传递给组合函数的调用者。
- identity:static 方法。返回一个始终返回其输入参数的函数。
3.1.3 方法举例
1)apply
测试代码:
Function<String, String> function1 = s -> s.toUpperCase();
return function1.apply(str);
}
public static void main(String[] args) {
System.out.println(upString("hello!"));
}
通过 apply 调用具体的实现。执行结果:
2)compose
测试代码:
Function<String, String> function1 = s -> s.toUpperCase();
Function<String, String> function2 = s -> "my name is "+s;
String result = function1.compose(function2).apply("zhangSan");
System.out.println(result);
}
如结果所示:compose 先执行 function2 后执行 function1。
3)andThen
测试代码:
Function<String, String> function1 = s -> s.toUpperCase();
Function<String, String> function2 = s -> "my name is "+s;
String result = function1.andThen(function2).apply("zhangSan");
System.out.println(result);
}
执行结果:
如结果所示:
andThen 先执行 function1 后执行 function2。
- identity
测试代码:
Stream<String> stream = Stream.of("order", "good", "lab", "warehouse");
Map<String, Integer> map = stream.collect(Collectors.toMap(Function.identity(), String::length));
System.out.println(map);
}
执行结果:
3.2 Supplier
Supplier 的表现形式为不接受参数、只返回数据。
3.2.1 源码
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
3.2.2 方法说明
get:抽象方法。通过实现返回 T。
3.2.3 方法举例
SupplierTest(){
System.out.println(Math.random());
System.out.println(this.toString());
}
}
public static void main(String[] args) {
Supplier<SupplierTest> sup = SupplierTest::new;
System.out.println("调用一次");
sup.get();
System.out.println("调用二次");
sup.get();
}
执行结果:
如结果所示:Supplier 建立时并没有创建新类,每次调用 get 返回的值不是同一个。
3.3 Consumer
Consumer 接收一个参数,没有返回值。
3.3.1 源码
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
3.3.2 方法说明
- accept:对给定参数 T 执行一些操作。
- andThen:按顺序执行 Consumer -> after , 如果执行操作引发异常,该异常被传递给调用者。
3.3.3 方法举例
Consumer<String> consumer = s -> System.out.println("consumer_"+s);
Consumer<String> after = s -> System.out.println("after_"+s);
consumer.accept("isReady");
System.out.println("========================");
consumer.andThen(after).accept("is coming");
}
执行结果:
如结果所示:对同一个参数 T,通过 andThen 方法,先执行 consumer,再执行 fater。
3.4 Runnable
Runnable:Runnable 的表现形式为即没有参数也没有返回值。
3.4.1 源码
public interface Runnable {
public abstract void run();
}
3.4.2 方法说明
run:抽象方法。run 方法实现具体的内容,需要将 Runnale 放入到 Thread 中,通过 Thread 类中的 start () 方法启动线程,执行 run 中的内容。
3.4.3 方法举例
@Override
public void run() {
System.out.println("TestRun is running!");
}
}
public static void main(String[] args) {
Thread thread = new Thread(new TestRun());
thread.start();
}
执行结果:
如结果所示:当线程实行 start 方法时,执行 Runnable 的 run 方法中的内容。
4 Function 接口用法
Function 的主要用途是可以通过 lambda 表达式实现方法的内容。
4.1 差异处理
public class User {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 组员
*/
private List<User> parters;
}
public static void main(String[] args) {
User user =new User();
if(user ==null ||user.getAge() <18 ){
throw new RuntimeException("未成年!");
}
}
执行结果:
使用 Function 接口后的代码:
public interface testFunctionInfe {
/**
* 输入异常信息
* @param message
*/
void showExceptionMessage(String message);
}
public static testFunctionInfe doException(boolean flag){
return (message -> {
if (flag){
throw new RuntimeException(message);
}
});
}
public static void main(String[] args) {
User user =new User();
doException(user ==null ||user.getAge() <18).showExceptionMessage("未成年!");
}
执行结果:
使用 function 接口前后都抛出了指定的异常信息。
4.2 处理 if…else…
User user =new User();
if(user==null){
System.out.println("新增用户");
}else {
System.out.println("更新用户");
}
}
使用 Function 接口后的代码:
User user =new User();
Consumer trueConsumer = o -> {
System.out.println("新增用户");
};
Consumer falseCnotallow= o -> {
System.out.println("更新用户");
};
trueOrFalseMethdo(user).showExceptionMessage(trueConsumer,falseConsumer);
}
public static testFunctionInfe trueOrFalseMethdo(User user){
return ((trueConsumer, falseConsumer) -> {
if(user==null){
trueConsumer.accept(user);
}else {
falseConsumer.accept(user);
}
});
}
@FunctionalInterface
public interface testFunctionInfe {
/**
* 不同分处理不同的事情
* @param trueConsumer
* @param falseConsumer
*/
void showExceptionMessage(Consumer trueConsumer,Consumer falseConsumer);
}
执行结果:
4.3 处理多个 if
String flag="";
if("A".equals(flag)){
System.out.println("我是A");
}else if ("B".equals(flag)) {
System.out.println("我是B");
}else if ("C".equals(flag)) {
System.out.println("我是C");
}else {
System.out.println("没有对应的指令");
}
}
使用 Function 接口后的代码:
String flag="B";
Map<String, Runnable> map =initFunctionMap();
trueOrFalseMethdo(map.get(flag)==null).showExceptionMessage(()->{
System.out.println("没有相应指令");
},map.get(flag));
}
public static Map<String, Runnable> initFunctionMap(){
Map<String,Runnable> result = Maps.newHashMap();
result.put("A",()->{System.out.println("我是A");});
result.put("B",()->{System.out.println("我是B");});
result.put("C",()->{System.out.println("我是C");});
return result;
}
public static testFunctionInfe trueOrFalseMethdo(boolean flag){
return ((runnable, falseConsumer) -> {
if(flag){
runnable.run();
}else {
falseConsumer.run();
}
});
}
执行结果:
Function 函数式接口是 java 8 新加入的特性,可以和 lambda 表达式完美结合,是非常重要的特性,可以极大的简化代码。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK