范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

JAVA代码规范与编写高质量代码的建议(2)

  目录6. 行为参数化传递代码7. 接口验证优化与自定义注解8. 原型模式提高创建对象的性能9. CompleteFuture异步编程提高RPC效率10. AOP实现日志记录6. 行为参数化传递代码
  软件工程中一个众所周知的问题就是,不管你做什么,用户的需求肯定会变。比方说,有个应用程序是帮助农民了解自己的库存。这位农民可能想要一个查找库存中所有绿色苹果的功能。但到了第二天,他可能会告诉你:"其实我还想找出所有重量超过150克的苹果。"过了两天,农民又跑回来补充道:"要是我可以找出所有既是绿色,重量也超过150克的苹果,那就太棒了。"你要如何应对这样不断变化的需求?理想的状态下,应该把你的工作量降到最少。此外,类似的新功能实现起来还应该很简单,而且易于长期维护。
  行为参数化就是可以帮助你处理频繁变更的需求的一种软件开发模式
  就农场库存程序而言,你必须实现一个从列表中筛选绿苹果的功能6.1 初试牛刀:筛选绿苹果/**  * @author Marion  * @date 2022/5/13 18:08  */ public class Farm001 {     /**      * v1. 筛选绿色苹果      */     public static List filterGreenApples(List list) {         List ret = new ArrayList<>();         for (Apple apple : list) {             if (apple.getColor().equals(ColorEnums.GREEN.name())) {                 ret.add(apple);             }         }         return ret;     } }6.2 再展身手:把颜色作为参数    /**      * v2. 颜色作为参数      */     public static List filterRedApples(List list, ColorEnums color) {         List ret = new ArrayList<>();         for (Apple apple : list) {             if (apple.getColor().equals(color.name())) {                 ret.add(apple);             }         }         return ret;     }
  太简单了,对吧?让我们把例子再弄得复杂一点儿。这位农民又跑回来和你说:"要是能区分轻的苹果和重的苹果就太好了。重的苹果一般是重量大于150克。"/**  * v2: 筛选重量苹果  * @param flag true-比较颜色 false-比较重量  */ public static List filterGreenApples(List list, ColorEnums color, int wight, boolean flag) {     List ret = new ArrayList<>();     for (Apple apple : list) {         if (flag) {             if (apple.getColor().equals(color.name())) {                 ret.add(apple);             }         } else {             if (apple.getWeight() > wight) {                 ret.add(apple);             }         }     }     return ret; }6.3 行为参数化
  你在上一节中已经看到了,你需要一种比添加很多参数更好的方法来应对变化的需求。让我们后退一步来看看更高层次的抽象。一种可能的解决方案是对你的选择标准建模:你考虑的是苹果,需要根据Apple的某些属性(比如它是绿色的吗?重量超过150克吗?)来返回一个boolean值。我们把它称为谓词(即一个返回boolean值的函数)。让我们定义一个接口来对选择标准建模:@FunctionalInterface public interface ApplePredicate {     boolean filter(Apple apple); }
  你可以把这些标准看作filter方法的不同行为。你刚做的这些和"策略设计模式"相关,它让你定义一族算法,把它们封装起来(称为"策略"),然后在运行时选择一个算法6.4 第五次尝试:使用匿名类/**  * v3: 筛选绿色  */ Farm003.filterApples(apples, new ApplePredicate() {     @Override     public boolean filter(Apple apple) {         return apple.getColor().equals(ColorEnums.GREEN.name());     } });  Farm003.filterApples(apples, new ApplePredicate() {     @Override     public boolean filter(Apple apple) {         return apple.getColor().equals(ColorEnums.GREEN.name()) && apple.getWeight() > 100;     } }); /**  * v3: 筛选重量苹果  */ public static List filterApples(List list, ApplePredicate predicate) {     List ret = new ArrayList<>();     for (Apple apple : list) {         if (predicate.filter(apple)) {             ret.add(apple);         }     }     return ret; }
  第一,它往往很笨重,因为它占用了很多空间
  第二,很多程序员觉得它用起来很让人费解6.5 第六次尝试:使用Lambda表达式Farm003.filterApples(apples, apple -> apple.getColor().equals(ColorEnums.GREEN.name())); Farm003.filterApples(apples, apple -> apple.getColor().equals(ColorEnums.GREEN.name()) && apple.getWeight() > 100);6.6 第七次尝试:将List类型抽象化@FunctionalInterface public interface ApplePredicate {     boolean filter(T apple); }6.7 第八次尝试:使用Stream流过滤 /**  * v4: 筛选重量苹果  */ public static List filterApples(List list, ColorEnums color) {     return list.stream()             .filter(v -> v.getColor().equals(color.name()))             .collect(Collectors.toList()); }7. 接口验证优化与自定义注解
  validation主要是校验用户提交的数据的合法性,比如是否为空,密码是否符合规则,邮箱格式是否正确等等,校验框架比较多,用的比较多的是hibernate-validator, 也支持国际化,也可以自定义校验类型的注解,这里只是简单地演示校验框架在SpringBoot中的简单集成,要想了解更多可以参考 hibernate-validator。/**  * @author Marion  * @date 2022/5/13 14:38  */ @Data @NoArgsConstructor @AllArgsConstructor @Builder public class UserQuery {      private Long id;      @NotBlank     @Length(min = 4, max = 10)     private String name;      @NotBlank     @Email     private String email;      /**      * ^((13[0-9])|(15[^4,D])|(18[0,3-9]))d{8}$      */     @NotBlank     //@Pattern(regexp = "^((13[0-9])|(15[^4,D])|(18[0,3-9]))d{8}#34;, message = "手机号格式不正确")     @Phone     private String phone;      @Min(value = 18)     @Max(value = 200)     private int age;      @NotBlank     @Length(min = 4, max = 12, message = "昵称4-12位")     private String nickname; }/**  * 全局异常处理器增加对APIException的拦截,并修改异常时返回的数据格式  * @author Marion  * @date 2022/5/13 14:47  */ @RestControllerAdvice public class GlobalExceptionHandler {      @ExceptionHandler(MethodArgumentNotValidException.class)     public AppResponse validationException(MethodArgumentNotValidException e) {         System.out.println(e.getMessage());         FieldError fieldError = e.getBindingResult().getFieldError();         return AppResponse.builder()                 .code(400)                 .message(fieldError.getDefaultMessage())                 .build();     } }
  自定义验证注解/**  * @author Marion  * @date 2022/5/13 15:10  */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) @Constraint(validatedBy = PhoneValidator.class) public @interface Phone {      String message() default "手机号格式不正确";      Class<?>[] groups() default {};      Class<? extends Payload>[] payload() default {}; }/**  * @author Marion  * @date 2022/5/13 15:43  */ public class PhoneValidator implements ConstraintValidator {     @Override     public void initialize(Phone constraintAnnotation) {      }      @Override     public boolean isValid(String value, ConstraintValidatorContext context) {         if (!StringUtils.isEmpty(value)) {             return isPhone(value);         }         return false;     }      private boolean isPhone(String phone) {         return phone.matches("^((13[0-9])|(15[^4,D])|(18[0,3-9]))d{8}#34;);     } }8. 原型模式提高创建对象的性能对于构造参数耗时多的使用原型模式更快轻量级对象new效率高于原型模式/**  * @author Marion  * @date 2022/5/13 16:16  */ @Data @NoArgsConstructor public class UserDTO implements Cloneable {      public UserDTO(int id, String name) {         if (name.length() != 0) {             name = name.substring(0, 1);         }         this.id = id;         this.name = name;     }      private int id;      private String name;      @Override     public Object clone() {         UserDTO userDTO = null;         try {             userDTO = (UserDTO) super.clone();         } catch (CloneNotSupportedException e) {             e.printStackTrace();         }         return userDTO;     } }
  benchmark进行性能测试/**  * 原型模式创建对象  * 1. 轻量级对象new效率高于原型模式  * @author Marion  * @date 2022/5/13 16:16  */ public class Demo008 {      @Benchmark     @BenchmarkMode(Mode.AverageTime)     @Warmup(iterations = 1, timeUnit = TimeUnit.SECONDS)     @Measurement(iterations = 1, time = 5, timeUnit = TimeUnit.SECONDS)     @OutputTimeUnit(TimeUnit.SECONDS)     @Fork(1)     @Threads(1)     public static void newUserDTO() {         long start = System.currentTimeMillis();         for (int i = 0; i < 10000000; i++) {             UserDTO userDTO = new UserDTO(1, "张三");             userDTO.setName("张三");         }         long end = System.currentTimeMillis();         System.out.println("newUserDTO="  + (end -start) + "ms");     }      @Benchmark     @BenchmarkMode(Mode.AverageTime)     @Warmup(iterations = 1, timeUnit = TimeUnit.SECONDS)     @Measurement(iterations = 1, time = 5, timeUnit = TimeUnit.SECONDS)     @OutputTimeUnit(TimeUnit.SECONDS)     @Fork(1)     @Threads(1)     public static void cloneUserDTO() {         long start = System.currentTimeMillis();         UserDTO userDTO = new UserDTO(1, "张三");         for (int i = 0; i < 10000000; i++) {             UserDTO clone =  (UserDTO) userDTO.clone();             clone.setName("李四");         }         long end = System.currentTimeMillis();         System.out.println("cloneUserDTO="  + (end -start) + "ms");     }      public static void main(String[] args) throws RunnerException {         OptionsBuilder builder = new OptionsBuilder();         Options build = builder.include(Demo008.class.getSimpleName())                 .forks(1)                 .build();         new Runner(build).run();     }  } 9. CompleteFuture异步编程提高RPC效率
  很多语言(如JavaScript)提供了异步回调,一些Java中间件(如Netty、Guava)也提供了异步回调API,为开发者带来了更好的异步编程工具。Java 8提供了一个新的、具备异步回调能力的工具类——CompletableFuture,该类实现了Future接口,还具备函数式编程的能力。
  使用CompletableFuture进行多个RPC调用/**  * @author Marion  * @date 2022/5/13 17:41  */ @Service public class ShopService {      /**      * v1: 串行执行      */     public void goods() {         StopWatch stopWatch = new StopWatch();         stopWatch.start();          System.out.println(userInfo());         System.out.println(goodsInfo());         System.out.println(commentInfo());          stopWatch.stop();         System.out.println("[goods] execute time=" + stopWatch.getTotalTimeMillis() + "ms");     }      public void syncGoods() throws ExecutionException, InterruptedException {         StopWatch stopWatch = new StopWatch();         stopWatch.start();          CompletableFuture s1 = CompletableFuture.supplyAsync(this::userInfo);         CompletableFuture s2 = CompletableFuture.supplyAsync(this::goodsInfo);         CompletableFuture s3 = CompletableFuture.supplyAsync(this::commentInfo);          CompletableFuture objectCompletableFuture = s1.thenCombine(s2, (o1, o2) -> o1 + ":" + o2)                 .thenCombine(s3, (o1, o2) -> o1 + ":" + o2);         String ret = (String) objectCompletableFuture.get();         System.out.println(ret);          stopWatch.stop();         System.out.println("[goods] execute time=" + stopWatch.getTotalTimeMillis() + "ms");     }      public String userInfo() {         try {             Thread.sleep(200L);         } catch (InterruptedException e) {             e.printStackTrace();         }         return "userInfo";     }      public String goodsInfo() {         try {             Thread.sleep(200L);         } catch (InterruptedException e) {             e.printStackTrace();         }         return "goods";     }      public String commentInfo() {         try {             Thread.sleep(200L);         } catch (InterruptedException e) {             e.printStackTrace();         }         return "commentInfo";     } }10. AOP实现日志记录
  通过AOP进行接口输入输出参数、执行时间打印package com.marion.codestandard.demo010;  import com.fasterxml.jackson.databind.ObjectMapper; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;  import javax.servlet.http.HttpServletRequest;  /**  * @author Marion  * @date 2022/5/13 18:17  */ @Aspect @Component public class AopLog {     private Logger logger = LoggerFactory.getLogger(this.getClass());     ThreadLocal startTime = new ThreadLocal<>();      /**      * 定义切点      */     @Pointcut(value = "execution(* com.marion.codestandard.demo010.*.*(..))")     public void aopWebLog() {     }      /**      * 使用环绕通知      */     @Around("aopWebLog()")     public Object myLogger(ProceedingJoinPoint pjp) throws Throwable {         startTime.set(System.currentTimeMillis());         //使用ServletRequestAttributes请求上下文获取方法更多         ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();         HttpServletRequest request = attributes.getRequest();         String className = pjp.getSignature().getDeclaringTypeName();         String methodName = pjp.getSignature().getName();         //使用数组来获取参数         Object[] array = pjp.getArgs();         ObjectMapper mapper = new ObjectMapper();         //执行函数前打印日志         logger.info("调用前:{}:{},传递的参数为:{}", className, methodName, mapper.writeValueAsString(array));         logger.info("URL:{}", request.getRequestURL().toString());         logger.info("IP地址:{}", request.getRemoteAddr());         //调用整个目标函数执行         Object obj = pjp.proceed();         //执行函数后打印日志         logger.info("调用后:{}:{},返回值为:{}", className, methodName, mapper.writeValueAsString(obj));         logger.info("耗时:{}ms", System.currentTimeMillis() - startTime.get());         return obj;     } }项目代码
  https://gitee.com/zeus-maker/marion-code-standard
  《编写高质量代码:改善Java程序的151个建议 》
  微信公众号【后端研发Marion】
坐不住了!苹果卖爆后华为大量上市高通新机,意味着什么?说实话,华为的旗舰机价格太贵,相对于苹果来说,苹果手机就有了明显的优势,品牌,价格,苹果优势。别谈什么爱国,这和爱国扯不上关系。我的钱做主。虽然我买不起华为,但是我也买不起苹果。苹背靠谷歌,DeepMind史上首度盈利,收入来源成谜一直以强研发和烧钱著称的谷歌旗下人工智能研究型企业DeepMind公司周二提交年度业绩报告,显示了历史上的首度盈利。在经历了过去几年每年数亿美元的亏损后,2020年DeepMind有人说现在的女生月薪四五千,却能买最新的苹果手机,过着健身旅游的优质生活,你怎么看?首先靠自己生活,活得精彩一点是很有必要的。不要在意别人怎么活,把自己的生活过得精彩一点也是很有必要的。现在健身房一般都不贵(品牌连锁,私教除外),因为教练会给你约定一周一次或者一周人间丨地表最强菜贩子王建文一年卖菜4。6亿,想让全国都知道寿光蔬菜的好来源海报新闻大众网海报新闻记者董昊骞张海振寿光报道把寿光蔬菜推广到全国,是王建文多年的梦想。这个梦想跟成长经历有关。1990年王建文在寿光一户农家出生,自幼看着父母和其他村民一样,有激情的人可以让世界变得更好!乔布斯去世10周年苹果CEO库克发文缅怀FX168财经报社(北美)讯周二(10月5日)是苹果联合创始人史蒂夫乔布斯逝世十周年。和往年一样,苹果首席执行官蒂姆库克再次向乔布斯致敬。库克在推特上引用了乔布斯的话,说有激情的人数读比亚迪9月销量全系累计销售7。9万辆,新车海豚成绩单出炉文懂车帝原创魏微懂车帝原创行业国庆长假期间,比亚迪汽车发布了最新的销量表现。比亚迪发布数据显示,比亚迪乘用车9月全系销售79037辆,同比增长93。2环比增长16。9。9月新能源汽荣耀6000mAh新机备货,虽有6nm芯片,但8256G却低至2399今年独立后的荣耀猛冲市场,从上半年开始就疯狂发布新机,意在用机海战术找回此前因为禁令流失的国内市场。大家也看到了,截至目前,荣耀已经有V40系列荣耀50系列荣耀Magic3系列荣耀国产手机这么多,为什么天天说要支持华为手机呢?我个人觉得国产手机大家能支持的都应该去支持!支持国货之光!华为手机比较多少支持主要是以下几个方面1华为手机的质量过关,设计比较符合国人的需求。功能丰富,拍照一流。2华为投入研发经费全球芯片短缺,比亚迪逆风翻盘,9月乘用车全系销售79037辆比亚迪作为一家集科技与技术实力并存的企业,芯片问题似乎毫不影响比亚迪向前的脚步,反而让比亚迪,领跑了新能源汽车行业发展。拿下了紧凑级轿车和紧凑级SUV,插混销量榜的榜首,再一次用实脸书Ins崩了6小时!公司股价也跌了据路透社报道,因宕机近6个小时而陷入大规模瘫痪,社交媒体脸书Instagram以及即时通讯软件WhatsApp4日下午开始恢复部分运营。报道称,美东时间4日中午前后,上述三家平台均比尔盖茨的幸运突变将微软公司带入软件产业领导地位的产品是MSDOS,它是IBM电脑和IBM兼容机的操作系统。然而DOS软件最初不是微软开发的,它的开发商是西雅图电脑公司,那时的名字叫QDOS(代表快
让直播变得更简单,加来众科CM8触摸屏数字直播声卡为直播而生,是加来众科产品系列的核心理念,加来众科经过多次改良,精心打造了CM触摸屏数字直播声卡,这款触摸屏直播声卡,是专门为K歌直播设计得全新K歌直播神器。目前市面上的传统手机直从iPhone转到一加7Pro什么感受?这也意味着,随着国产手机的不断进步与发展,越来越多的iPhone用户开始转向了安卓手机。那么这些iPhone用户流向了哪些手机品牌呢?最近这段时间,就有不少用户在微博上分享了自己的iPhone12连转接头都不送了,想听无损音频有好办法吗?等了一年又一年,支持5G的iPhone12终于上市了,这次iPhone12连手机连转接头都不送了,想听有线音频,有没有更好的办法?以前,我们只需要在手机上播放歌曲,插上耳机就能享受加来众科M50专业监听耳机,让听音乐变得有仪式感直播行业的火热程度,大家是有目共睹的,这一行业的迅速发展,也带动了许多相关产业的发展,特别是直播设备也越来越多了,而耳机作为直播中必不可少的设备,不但能用于直播监听,在日常娱乐生活音乐手机为啥越来越少了?音乐手机,曾经无限风光的产品,现在为啥越来越少了?就连主打音乐手机的ViVO最近也很少更新其音乐手机产品线,是什么原因?我们有做一期视频,在知乎和B站都有,有兴趣的可以去我们视频主THX到底是个啥你可能看到过这个标志(THX),但你知道它表示什么吗?THX不是Thanks的缩写,而是视听感受的忠实守护者。星球大战帝国反击战上映后,导演乔治卢卡斯发现虽然声音录制和影片拍摄技术hifi把功率做大是否是一个骗局?此文我们有做一个视频,觉得文字不方便看的话可以看我们的视频。经常看到有些人说,拿普通手机推耳机就够用了,耳机就是听个响,几mW的功率完全满足使用,HiFi就是智商税。hifi把功率华为新一代麒麟芯片将于9月6日发布,或集成5G基带8月19日,华为终端官方微博发布了IFA2019预告视频,宣告华为将参加9月6日柏林IFA2019大展!预告视频发出之后,网友们纷纷猜测在IFA2019上华为会有哪些大动作,是发布不惧地理限制华为智慧屏让亲情汇聚一屏之间9月19日,华为在德国慕尼黑一下带来了两款重磅智能终端产品华为Mate30系列和华为智慧屏。其中,华为智慧屏由于是智慧终端的新物种,受到了格外的关注。华为智慧屏很有可能掀起一场客厅会买的小伙伴双11开始准备新年礼物啦!华为平板M5青春版了解下?双11购物狂欢的号角已然吹响,不少小伙伴又开始摩拳擦掌准备买买买了!而且随着双11抢购的经验不断丰富,很多会买的小伙伴还会趁着优惠力度最大的时候把一年里需要的物品都买好。特别是双1华为nova6系列配备麒麟9904200mAh大电池让你爽玩一整天今年的5G手机竞争尤为激烈,但于近日发布的华为nova65G手机一经推出便成为了同档位最受欢迎的手机之一,受到nova星人的追捧。该机除了先进的105前置超广角双摄系统外,搭载的麒