• Java程序猿如何用Supplier来优化代码?


    之前的文章《Supplier的作用及其使用》提到过Supplier,昨天后台有小伙伴问到有没有实际的案例。今天来分享一下实际项目的用法,以此提高代码的健壮性。

    log日志打印,大家都应该不陌生,生产上不会用System.out.println()的方式,因为可能会造成死锁

    我们日常调试可能都会用debug模式进行,然后生产环境的日志级别是info,debug不会输出,但是这里的入参只是不会输出,但是会执行,这样一看来,不是太影响自己代码的质量了么?有没有一种方式,如果不是debug模式,就不执行,是dubug模式就执行的办法呢?

    当然有,那就是Supplier,我们开始一个Demo,来展示一下。

    有一个参数为整数类型的x的Get请求

        @GetMapping
        public String getInfos(@RequestParam int x) {
    
            // log日志测试
            logTest(x);
            return "success";
        }
    
        private void logTest(int x) {
            log.info("value:{}", "info级别输出");
            log.debug("value2:{}", debugInfo());
        }
    
        private static String debugInfo() {
            System.out.println("debugInfo执行了");
            return "debug级别输出";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    我们打印两条日志,注意看这里,我们没有配置任何日志级别,那么默认就是Info,是不输出debug的日志。

    但是我们会发现却执行了debugInfo(),这太影响性能了。

    那该如何改进呢?通过上一篇文章《Supplier的作用及其使用》我们知道,Supplier可以创建一个Supplier实例,只有调用Supplier的get方法的时候,才会去真正的执行。

    那么我们说干就干。先来封装一个工具类:

    package com.ossa.web.util;
    
    
    import java.util.Objects;
    import java.util.function.Supplier;
    
    public class LazyUtil<T> implements Supplier<T> {
    
    
        private final Supplier<T> supplier;
    
        public static <T> LazyUtil<T> of(Supplier<T> supplier) {
            Objects.requireNonNull(supplier, "supplier is null");
            if (supplier instanceof LazyUtil) {
                return (LazyUtil<T>) supplier;
            } else {
                return new LazyUtil<T>(supplier);
            }
        }
    
        private LazyUtil(Supplier<T> supplier) {
            this.supplier = supplier;
        }
    
        @Override
        public T get() {
            return supplier.get();
        }
    
        @Override
        public String toString() {
            return get().toString();
        }
    }
    
    
    • 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

    设计思想:这个工具类就是创建一个Supplier实例,如果输出该实例的话,就会默认创建调用toString()方法(这个知道为什么吧0.0,不知道百度喽)

    我们来使用一下:

    @GetMapping
    public String getInfos(@RequestParam int x) {
    
        // log日志测试
        logTest(x);
        return "success";
    }
    
    private void logTest(int x) {
        log.info("value:{}", "info级别输出");
        log.debug("value2:{}", LazyUtil.of(AppRun::debugInfo));
    
    }
    
    private static String debugInfo() {
        System.out.println("debugInfo执行了");
        return "debug级别输出";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    OK,果然没有触发debugInfo()方法。

    我们在看看JDK中是如何应用的,JDK8的新特性Optional,大家没有忘吧,用来判空的嘛,开发中大家也会经常用到。

    有如下场景:如果缓存中没有数据,则需要从数据中获取。

    大家会怎么写?if...eles...???看看下面的写法如何?

        @GetMapping
        public String getInfos(@RequestParam int x) {
    
            // log日志测试
            logTest(x);
            // 懒加载,提高性能
            return Optional.ofNullable(getCache(x)).orElseGet(this::getDB);
        }
    
        private String getCache(int x) {
            if (x == 1) return null;
    
            return "缓存中获取";
        }
    
        private String getDB() {
            System.out.println("getDB执行了");
            return "数据库中获取中获取";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这样只有前者为空才会真正执行后面的方法。

    有人会问:就算不执行,不也是创建了Supplier实例?这么频繁的创建不会造成性能问题吗?

    问的好。

    但只是创建了一个Supplier实例,没有任何属性,非常的轻量,所占用的空间非常小,当然也会分配到年轻代,并不会分配到老年代,走大规模的GC周期。并且相对于需要执行的代码,代价真是微乎其微了…

    这个Supplier提供的懒加载机制,真的太棒了~

    下面附上完整代码,以供参考,如果不足,多提意见,感觉不爽,直接开骂,大家开心就好了~都是一家人们,让我们一起喊出我们的口号:奥里给!!!

    package com.ossa.web;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Optional;
    
    
    @Slf4j
    @RestController
    @SpringBootApplication
    public class AppRun {
        public static void main(String[] args) {
            SpringApplication.run(AppRun.class, args);
        }
    
        @GetMapping
        public String getInfos(@RequestParam int x) {
    
            // log日志测试
            logTest(x);
            // 懒加载,提高性能
    //        return Optional.ofNullable(getCache(x)).orElseGet(this::getDB);
            return Optional.ofNullable(getCache(x)).orElse(getDB());
        }
    
        private void logTest(int x) {
            log.info("value:{}", "info级别输出");
    //        log.debug("value2:{}", LazyUtil.of(AppRun::debugInfo));
            log.debug("value2:{}", debugInfo());
        }
    
        private static String debugInfo() {
            System.out.println("debugInfo执行了");
            return "debug级别输出";
        }
    
        private String getCache(int x) {
            if (x == 1) return null;
    
            return "缓存中获取";
        }
    
        private String getDB() {
            System.out.println("getDB执行了");
            return "数据库中获取中获取";
        }
    }
    
    • 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
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
  • 相关阅读:
    【Hack The Box】Linux练习-- Forge
    Vue笔记3(计算属性,监视属性,绑定样式)
    基于JAVA的校园服务小程序设计
    this的四个绑定规则
    第七节:类和对象【一】【java】
    CSS调试实例
    产品推荐 | 基于XILINX K7 XC7K325T的PCIe_CameraLink图像模拟源
    学习vue第一天
    如何获取用户的ip地址
    智能驾驶汽车虚拟仿真视频数据理解(一)
  • 原文地址:https://blog.csdn.net/CSDN_SAVIOR/article/details/128186886