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