Function源码解析与实践

function,源码,解析,实践 · 浏览次数 : 245

小编点评

4 Function接口用法Function的主要用途是可以通过lambda 表达式实现方法的内容。4.1 差异处理原代码:@Datapublic class User { ... }使用Function接口后的代码:public static void main(String[] args) { User user =new User(); Consumer trueConsumer = o -> { System.out.println(\"新增用户\"); }; Consumer falseConsumer= 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); } });} }执行结果:5 4.2 处理if…else…原代码:public static void main(String[] args) { 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接口后的代码:public static void main(String[] args) { 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;}执行结果:5 4.3 处理多个if原代码:public static void main(String[] args) { 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接口后的代码:public static void main(String[] args) { 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;}执行结果:5

正文

作者:陈昌浩

1 导读

if…else…在代码中经常使用,听说可以通过Java 8的Function接口来消灭if…else…!Function接口是什么?如果通过Function接口接口消灭if…else…呢?让我们一起来探索一下吧。

2 Function接口

Function接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,Function接口可以被隐式转换为 lambda 表达式。可以通过FunctionalInterface注解来校验Function接口的正确性。Java 8允许在接口中加入具体方法。接口中的具体方法有两种,default方法和static方法。

@FunctionalInterface
interface TestFunctionService
{
    void addHttp(String url);
}

那么就可以使用Lambda表达式来表示该接口的一个实现。

TestFunctionService testFunctionService = url -> System.out.println("http:" + url);

2.1 FunctionalInterface

2.1.1 源码
@Documented
@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 源码
@FunctionalInterface
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

测试代码:

public  String upString(String str){
    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

测试代码:

public static void main(String[] args) {
    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

测试代码:

public static void main(String[] args) {
    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

测试代码:

public static void main(String[] args) {
    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 源码
@FunctionalInterface
public interface Supplier<T> {
    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
3.2.2 方法说明

get:抽象方法。通过实现返回T。

3.2.3 方法举例
public class SupplierTest {
    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 源码
@FunctionalInterface
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 方法举例
public static void main(String[] args) {
    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 源码
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
3.4.2 方法说明

run:抽象方法。run方法实现具体的内容,需要将Runnale放入到Thread中,通过Thread类中的start()方法启动线程,执行run中的内容。

3.4.3 方法举例
public class TestRun implements Runnable {
    @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 差异处理

原代码:

@Data
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接口后的代码:

@FunctionalInterface
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…

原代码:

public static void main(String[] args) {
    User user =new User();
    if(user==null){
        System.out.println("新增用户");
    }else {
        System.out.println("更新用户");
    }
}

使用Function接口后的代码:

public static void main(String[] args) {
    User user =new User();
    Consumer trueConsumer = o -> {
        System.out.println("新增用户");
    };
    Consumer falseConsumer= 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

原代码:

public static void main(String[] args) {
    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接口后的代码:

public static void main(String[] args) {
    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();
        }
    });
}

执行结果:

5 总结

Function函数式接口是java 8新加入的特性,可以和lambda表达式完美结合,是非常重要的特性,可以极大的简化代码。

与Function源码解析与实践相似的内容:

Function源码解析与实践

作者:陈昌浩 1 导读 if…else…在代码中经常使用,听说可以通过Java 8的Function接口来消灭if…else…!Function接口是什么?如果通过Function接口接口消灭if…else…呢?让我们一起来探索一下吧。 2 Function接口 Function接口就是一个有且仅有

Vue源码学习(十一):计算属性computed初步学习

好家伙, 1.Computed实现原理 if (opts.computed) { initComputed(vm,opts.computed); } function initComputed(vm, computed) { // 存放计算属性的watcher const watchers = vm

r0tracer 源码分析

使用方法 修改r0tracer.js文件最底部处的代码,开启某一个Hook模式。 function main() { Java.perform(function () { console.Purple("r0tracer begin ... !") //0. 增加精简模式,就是以彩虹色只显示进出函数

Vue源码学习(六):(支线)渲染函数中with(),call()的使用以及一些思考

好家伙, 昨天,在学习vue源码的过程中,看到了这个玩意 嘶,看不太懂,研究一下 1.上下文 这段出现vue模板编译的虚拟node部分 export function renderMixin(Vue) { Vue.prototype._c = function () { //创建标签 return

Azure Terraform(十二)利用 Terraform 将文件上传到 Azure Blob Storage

一,引言 本篇文章中,我门将学习如何利用 Terraform 将 文件以及文件夹上传到 Azure Blob Storage,这个对于我们来说很方便,可以将一些不重要的内容也存储在源代码管理工具中! 开始今天的内容之前,我们先来看看今天的主角 Terraform fileset Function 根

深入探讨Function Calling:在Semantic Kernel中的应用实践

引言 上一章我们熟悉了 OpenAI 的 function calling 的执行原理,这一章节我们讲解一下 function calling 在 Semantic Kernel 的应用。 在OpenAIPromptExecutionSettings跟 LLM 交互过程中,ToolCallBehav

深入探讨Function Calling:实现外部函数调用的工作原理

引言 Function Calling 是一个允许大型语言模型(如 GPT)在生成文本的过程中调用外部函数或服务的功能。 Function Calling允许我们以 JSON 格式向 LLM 模型描述函数,并使用模型的固有推理能力来决定在生成响应之前是否调用该函数。模型本身不执行函数,而是生成包含函

VBA 对象数组排序算法分享

Function SrotObjectByProperty(objsToSort As Variant, PropertyName As String, Optional 降序 As Boolean = True) If IsEmpty(objsToSort) Then Exit Function

【Azure Developer】在Github Action中使用Azure/functions-container-action@v1配置Function App并成功部署Function Image

问题描述 使用Github Action,通过 Azure/functions-container-action@v1 插件来完成 yaml 文件的配置,并成功部署Function Image 的过程记录。 操作步骤 第一步: 准备Function的镜像文件 如在VS Code中,通过Termina

【Azure Function App】在ADF(Azure Data Factory)中调用 Azure Function 时候遇见 Failed to get MI access token

问题描述 在ADF(Azure Data Factory)中,调用Azure Function App中的Function,遇见了 Failed to get MI access token There was an error while calling endpoint with error m