> 文档中心 > Java程序猿如何用Supplier来优化代码?

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级别输出";    }

我们打印两条日志,注意看这里,我们没有配置任何日志级别,那么默认就是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();    }}

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

我们来使用一下:

@GetMappingpublic 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级别输出";}

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 "数据库中获取中获取";    }

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

有人会问:就算不执行,不也是创建了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@SpringBootApplicationpublic 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 "数据库中获取中获取";    }}