点击上方 IT牧场 ,选择 置顶或者星标

技术干货每日送达

来源:https://juejin.im/post/6844903983744548877

前言

在我们平常开发过程中,由于项目时间紧张,代码可以用就好,往往会忽视代码的质量问题。甚至有些复制粘贴过来,不加以整理规范。往往导致项目后期难以维护,更别说后续接手项目的人。所以啊,我们要编写出优雅的代码,方便你我他,岂不美哉?

下面分享一些我在开发中常用的编码中小建议,如有不妥,欢迎大家一起交流学习。

卫语句

卫语句,就是把复杂的条件表达式拆分成多个条件表达式。比如 多个 if-elseif-else 嵌套, 可以拆分成多个 if。如下面代码

代码:

-------------------- before  --------------------public void today() {if (isWeekend()) {if (isFee()) {System.out.println("study Android");} else {System.out.println("play a game");}} else {System.out.println("go to work");}
}-------------------- after  (建议) --------------------public void today() {// 提前过滤掉`特殊情况`if (!isWeekend()) {System.out.println("go to work");return; // 提前return}//提前过滤掉`特殊情况`if (isFee()) {System.out.println("study Android");return; // 提前return}// 更关注于 `核心业务`代码实现。System.out.println("play a game");
}

提前过滤掉特殊情况,更关注核心业务逻辑

小函数

我们平常开发的时候,应该编写小而美函数,避免函数过长。一般函数最好在15行以内(建议) 我们看看下面代码:

-------------------- before  --------------------if (age > 0 && age < 18){System.out.println("小孩子");
}if (number.length() == 11){System.out.println("符合手机号");
}-------------------- after (建议) --------------------private static boolean isChild(int age) {return age > 0 && age < 18;
}private static boolean isPhoneNumber(String number) {return number.length() == 11;
}if (isChild(age)){System.out.println("小孩子");
}if (isPhoneNumber(number)){System.out.println("符合手机号");
}
复制代码

把判断语句抽取成一个个小函数, 这样代码更加清晰明了。

迪米特法则

概念:

迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少了解。例如 当一条语句中 一个对象出现两个 .student.getName().equals("张三")) 就是代码坏味道的表现,如下代码所示。

代码:

-------------------- before  --------------------public class Student {private String name;public Student(String name) {this.name = name;}public String getName() {return name;}
}public static void main(String[] args) {Student student = new Student("张三");// 注意看这里,// 这里获取 student的name属性,在根据name属性进行判断if (StringUtils.isNotBlank(student.getName()) && student.getName().equals("张三")) {System.out.println("我的好朋友是 " + student.getName());}
}-------------------- after (建议) --------------------public class Student {... 省略name代码// 新增一个 判断是否是我的好朋友方法public boolean isGoodFriend(){return StringUtils.isNotBlank(this.name) && this.name.equals("张三");}
}public static void main(String[] args) {Student student = new Student("张三");// 根据迪米特法则,把判断逻辑,抽取到 Student 内部,暴露出方法(isGoodFriend)if (student.isGoodFriend()){System.out.println("我的好朋友是 " + student.getName());}
}

IDEA/Android Studio 抽取方法快捷键: option + command + M

Map 提取对象

我们在平常开发中,会使用到map,但是在面向对象开发理念中,一个 map的使用,往往就会错过了 Java Bean。建议使用 Java Bean 更直观。如下代码:

public static void main(String[] args) {-------------------- before  --------------------Map<String, String> studentMap = new HashMap<>();studentMap.put("张三", "男");studentMap.put("小红", "女");studentMap.put("李四", "男");studentMap.forEach((name, sex) -> {System.out.println(name + " : " + sex);});-------------------- after (建议)  --------------------List<Student> students = new ArrayList<>();students.add(new Student("张三", "男"));students.add(new Student("小红", "女"));students.add(new Student("李四", "男"));for (Student student : students) {System.out.println(student.getName() + ":" + student.getSex());}}

笔者在编写这点时候,有所顾虑。肯定有小伙伴跳出来说,mapbean 不是一样吗?用map 我还可以省去思考如何命名Class呢。但是从代码规范来说,这样代码设计不是更符合 Java 面向对象的思想吗?

Stream

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。使得代码调用起来更加优雅~ 直接来看代码:

public static void main(String[] args) {List<Student> students = new ArrayList<>();students.add(new Student("张三", "男"));students.add(new Student("李四", "男"));students.add(new Student("小红", "女"));students.add(new Student("小花", "女"));students.add(new Student("小红", "女"));-------------------- before  --------------------//统计男生个数//传统的 for each 循环遍历long boyCount = 0;for (Student student : students) {if (student.isBoy()) {boyCount++;}}System.out.println("男生个数 = " + boyCount);-------------------- after (建议)  --------------------//统计男生个数//stream 流遍历long count = students.stream().filter(Student::isBoy) // 等同于.filter(student -> student.isBoy()).count();System.out.println("男生个数 = " + boyCount);
}

相比与 传统的 For 循环,更推荐大家使用 stream 遍历。stream 流的链式调用,还有许多骚操作,如 sorted, map, collect等操作符,可以省去不必要if-elsecount等判断逻辑。

多态

Java 三大特性之一,多态,相信大家都不会陌生,多态的好处就是根据对象不同类型采取不同的的行为。我们常常在编写 switch 语句的时候,如果改用多态,可以把每个分支,抽取到一个子类内的覆写函数中,这就更加灵活。

我们有这样一个需求,编写一个简单计算器方法,我们先来看一小段代码:

    -------------------- before  --------------------public static int getResult(int numberA, int numberB, String operate) {int result = 0;switch (operate) {case "+":result = numberA + numberB;break;case "-":result = numberA - numberB;break;case "*":result = numberA * numberB;break;case "/":result = numberA / numberB;break;}return result;}-------------------- after (建议)  --------------------abstract class Operate {abstract int compute(int numberA, int numberB);}class AddOperate extends Operate {@Overrideint compute(int numberA, int numberB) {// TODO 在这里处理相关逻辑return numberA + numberB;}}... SubOperate, MulOperate, DivOperate 也和 AddOperate一样这里就不一一贴出public static int getResult(int numberA, int numberB, String operate) {int result = 0;switch (operate) {case "+":result = new AddOperate().compute(numberA, numberB);break;case "-":result = new SubOperate().compute(numberA, numberB);break;case "*":result = new MulOperate().compute(numberA, numberB);break;case "/":result = new DivOperate().compute(numberA, numberB);break;}return result;}

有小伙伴可能会说,你这不是更复杂了吗?

对比起单纯的switch,我们可以这样理解:

  • 虽然在类上有所增加,但是通过多态,把对应操作的逻辑分离出来,使得代码耦合度降低。

  • 如果要修改对应加法的逻辑, 我们只需要修改对应 AddOperate类就可以了。避免直接修改getResult 方法

  • 代码可读性更好,语义更加明确。

但是这里会存在一些问题,如果我们新增一个平方根平方等计算方式, 就需要修改 switch 里面的逻辑,新增一个条件分支。下面我们再来看看更进一步的优化。

反射

通过上面例子,我们可以进一步优化,通过反射生成对应的 Class,然后在调用compute方法。如下代码:

public static <T extends Operate> int getResult(int numberA, int numberB, Class<T> clz) {int result = 0;try {return clz.newInstance().compute(numberA, numberB);} catch (InstantiationException | IllegalAccessException e) {e.printStackTrace();return result;}
}public static void main(String[] args) {// 调用的时候直接传递 class 即可System.out.println(getResult(1, 2, SumOpearte.class));
}

根据传入 class 参数,然后生成对应 Opearte处理类, 对比多态方式,我们这里采用反射,使得代码耦合度大大降低,如果在增加平方根平方等计算方式。我们只需要 新增一个 class 继承 Opearte 即可,getResult 不用做任何修改。

需要注意的是,不是所有switch语句都需要这样替换, 在面对简单的 switch语句,就不必要了, 避免过度设计的嫌疑。如下代码:

public String getResult(int typeCode) {String type = "";switch (typeCode) {case 0:type = "加法";break;case 1:type = "减法";break;case 2:type = "乘法";break;case 3:type = "除法";break;}return type;
}

干货分享

最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!

•001:《Java并发与高并发解决方案》学习笔记;•002:《深入JVM内核——原理、诊断与优化》学习笔记;•003:《Java面试宝典》•004:《Docker开源书》•005:《Kubernetes开源书》•006:《DDD速成(领域驱动设计速成)》•007:全部•008:加技术群讨论

近期热文

•LinkedBlockingQueue vs ConcurrentLinkedQueue•解读Java 8 中为并发而生的 ConcurrentHashMap•Redis性能监控指标汇总•最全的DevOps工具集合,再也不怕选型了!•微服务架构下,解决数据库跨库查询的一些思路•聊聊大厂面试官必问的 MySQL 锁机制

关注我

喜欢就点个"在看"呗^_^

[解锁新姿势] 分享 7 个优化代码的技巧相关推荐

  1. [解锁新姿势] 兄dei,你代码需要优化了

    黑客(程序员)也是创作者,与画家.建筑师.作家一样. --<黑客与画家> 前言 在我们平常开发过程中,由于项目时间紧张,代码可以用就好,往往会忽视代码的质量问题.甚至有些复制粘贴过来,不加 ...

  2. [解锁新姿势] 兄dei,你代码需要优化了

    前言 在我们平常开发过程中,由于项目时间紧张,代码可以用就好,往往会忽视代码的质量问题.甚至有些复制粘贴过来,不加以整理规范.往往导致项目后期难以维护,更别说后续接手项目的人.所以啊,我们要编写出优雅 ...

  3. [解锁新姿势] 回想起被 `if-else` 支配的恐惧,我们要打倒 if - else

    前言 [解锁新姿势] 兄dei,你代码需要优化了 在之前文章说到,简单 if-else,可以使用 卫语句 进行优化.但是在实际开发中,往往不是简单 if-else 结构,我们通常会不经意间写下如下代码 ...

  4. [解锁新姿势] 兄dei 我感觉你在写bug

    前言: 继上篇 [解锁新姿势] 兄dei,你代码需要优化了 介绍一些代码的优化的小技巧. 但是我们除了在代码编写上需要优雅, 还需要编写对应的测试用例, 以此来保证代码的质量. 在这篇我们继续在学习如 ...

  5. android解锁win,Win10电脑解锁新姿势:WP/安卓手机、微软手环当钥匙

    IT之家讯 微软在官方网站公布了Win10的开发路线图,其中描述了目前已经实现的功能.正在预览测试以及正在开发中的功能.根据描述,微软正在开发一种全新的Win10电脑解锁方式. 首先,你可以使用自己的 ...

  6. [解锁新姿势] 优化参数前置校验

    前言 我们通常写接口都会用到 @Valid 注解,通过 @NotNull,@NotEmpty 等等来简单校验我们的接口入参. 但是有些入参,需要查询数据库,这时候 @Valid 自带的校验注解,就满足 ...

  7. 解锁新姿势:探讨复杂的 if-else 语句“优雅处理”的思路

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:hyzhan43 juejin.im/post/5def65 ...

  8. windows编程 识别拖动_Quicker 解锁新姿势!Windows 还能这么用?

    不用记住软件复杂的快捷方式,轻轻按下鼠标滚轮,便可唤出当前软件的专属工具箱,一键启动原本要多次点击鼠标的操作,这样的时刻是否很美妙? Excel 选中表格数据加黑框并横向打印,一键搞定 Quicker ...

  9. 自定义控件从入门到轻生之---解锁新姿势

    所有blog局限于博主水平有限,很多不足之处大家可以指出共同探讨进步. 尊重原创转载请注明:From 倪大叶http://blog.csdn.net/renyi0109 侵权必究!虽然我不知道具体怎么 ...

最新文章

  1. (转)对微软那棵TreeView进行试用,主要是对CheckBox进行操作
  2. python写游戏脚本-python实现简单贪吃蛇游戏
  3. 7、GRANT:用户授权
  4. python Intel Realsense D435 多线程资源分配问题(卡住、卡死)
  5. HDU 1010题解这是一道简单的DFS加回溯题,看懂后就会对递归和回溯有较深刻的理解。...
  6. java applet 访问文件_使用JavaApplet访问数据库
  7. Ajax实例一:利用服务器计算
  8. xcode 4.2 开发2——TabelView
  9. 国脉信息学院计算机网络,福建工程学院国脉信息学院《计算机网络模拟题》
  10. 前端实战项目:vue+elementUI管理平台
  11. 3.1 数值分析: 迭代法的基本思想
  12. 写在前面(ShenYu)
  13. h桥控制电机刹车_基于H桥控制直流电机驱动电路设计
  14. MMORPG的常规技能系统
  15. 作为软件测试人员,这些常用的性能测试工具你一定要知道
  16. 正则(?=)(?:)
  17. 神经网络—卷积神经网络CNN
  18. 数学建模--(2.2)拟合模型
  19. qq批量登录软件_QQ群控高效管理,引流过万不是问题!
  20. 算法工程师5——计算机视觉知识点概览

热门文章

  1. console的用法
  2. 10月30日科技资讯|腾讯云推出首款自研服务器星星海;苹果新款Mac Pro整套配齐超30万;Fedora 31稳定版发布|极客头条
  3. bugfree 检测不到mysql_安装bugfree时,提示Mysql未安装,找了网上的方法更改代码,但是还没有得到解决,怎么办?...
  4. Python爬虫新手入门教学(二):爬取小说
  5. 布伦特原油 和 美原油双原油对冲套利程序化策略解析
  6. TimeSpan格式化
  7. html 禁止gif自动播放,通过CSS或JS实现gif动态图片的停止与播放
  8. RESTful 个人理解总结
  9. java数据长度_存储单位(字节)
  10. STM32F0系列内部高速时钟的配置方法