首页 > 其他分享 >15 个写代码的好习惯(可以减少 80% 非业务的 bug)

15 个写代码的好习惯(可以减少 80% 非业务的 bug)

时间:2024-01-26 16:59:27浏览次数:25  
标签:缓存 15 代码 80% 数据库 线程 接口 考虑 bug

引言

作为一名刚入行的程序员,平时在编写代码时最好养成一些好习惯,这样可以避免或减少各种非业务的 bug,从而提高开发效率,这里总结了常见的 15 个平时写代码的好习惯,希望对你有所帮助。

1. 修改完代码,记得自测一下

「改完代码,自测一下」 是每位程序员必备的基本素养。尤其不要抱有这种侥幸「心理:我只是改了一个变量或者我只改了一行配置代码,不用自测了」

改完代码,尽量要求自己都去测试一下哈,可以规避很多不必要bug的。

2. 方法入参尽量都检验

入参校验也是每个程序员必备的基本素养。你的方法处理,「必须先校验参数」。比如入参是否允许为空,入参长度是否符合你的预期长度。这个尽量养成习惯吧,很多「低级bug」都是「不校验参数」导致的。

如果你的数据库字段设置为varchar(16),对方传了一个32位的字符串过来,你不校验参数,「插入数据库直接异常」了。

3.对于复杂的代码逻辑,添加清楚的注释

写代码的时候,是没有必要写太多的注释的,好的方法变量命名就是最好的注释。但是,如果是「业务逻辑很复杂的代码」,真的非常有必要写「清楚注释」。清楚的注释,更有利于后面的维护。

4. 使用完IO资源流,需要关闭

应该大家都有过这样的经历,windows系统桌面如果「打开太多文件」或者系统软件,就会觉得电脑很卡。当然,我们linux服务器也一样,平时操作文件,或者数据库连接,IO资源流如果没关闭,那么这个IO资源就会被它占着,这样别人就没有办法用了,这就造成「资源浪费」

FileInputStream fdIn = null;
try {
    fdIn = new FileInputStream(new File("/jay.txt"));
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
}finally {
    try {
        if (fdIn != null) {
            fdIn.close();
        }
    } catch (IOException e) {
        log.error(e);
    }
}

5.代码采取措施避免运行时错误(如数组边界溢出,被零除等)

日常开发中,我们需要采取措施规避「数组边界溢出,被零整除,空指针」等运行时错误。

类似代码比较常见:

String name = list.get(1).getName(); //list可能越界,因为不一定有2个元素哈

所以,应该「采取措施,预防一下数组边界溢出」,正例:

if ( CollectionsUtil.isNotEmpty(list) && list.size() > 1) {
  String name = list.get(1).getName(); 
}

6.写完代码,脑洞一下多线程执行会怎样,注意并发一致性问题

我们经常见的一些业务场景,就是先查下有没有记录,再进行对应的操作(比如修改)。但是呢,(查询+修改)合在一起不是原子操作哦,脑洞下多线程,就会发现有问题了。

7.获取对象的属性,先判断对象是否为空

平时空指针异常太常见了,一个手抖不注意,就导致空指针报到生产环境去了。

所以,你要获取对象的属性时,尽量不要相信「理论上不为空」,我们顺手养成习惯判断一下是否为空,再获取对象的属性。正例:

if(object!=null){
   String name = object.getName();
}

8. 多线程异步优先考虑恰当的线程池,而不是 new thread,同时考虑线程池是否隔离

为什么优先使用线程池?使用线程池有如下这几点好处:

  • 它帮我们管理线程(避免增加创建线程和销毁线程的资源损耗)
  • 提高响应速度
  • 重复利用

同时呢,尽量不要所有业务都共用一个线程池,需要考虑「线程池隔离」。就是不同的关键业务,分配不同的线程池,然后线程池参数也要考虑恰当哈。

9. 手动写完代码业务的SQL,先拿去数据库跑一下,同时也 explain 看下执行计划

手动写完业务代码的SQL,可以先把它拿到数据库跑一下,看看有没有语法错误嘛。有些小伙伴不好的习惯就是,写完就把代码打包上去测试服务器,其实把SQL放到数据库执行一下,可以规避很多错误的。

同时呢,也用「explain看下你Sql的执行计划」,尤其走不走索引这一块。

explain select * from user where userid =10086 or age =18;

10.调用第三方接口,需要考虑异常处理,安全性,超时重试这几个点

调用第三方服务,或者分布式远程服务的的话,需要考虑如下:

  • 异常处理(比如,你调别人的接口,如果异常了,怎么处理,是重试还是当做失败)
  • 超时(没法预估对方接口一般多久返回,一般设置个超时断开时间,以保护你的接口)
  • 重试次数(你的接口调失败,需不需要重试,需要站在业务上角度思考这个问题)

注意:如果是转账等重要的第三方服务,还需要考虑「签名验签」「加密」等。

11. 接口需要考虑幂等性

接口是需要考虑幂等性的,尤其抢红包、转账这些重要接口。最直观的业务场景,就是「用户连着点击两次」,你的接口有没有hold住。

幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。

在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。

一般「幂等技术方案」有这几种:

  • 查询操作
  • 唯一索引
  • token机制,防止重复提交
  • 数据库的delete删除操作
  • 乐观锁
  • 悲观锁
  • Redis、zookeeper 分布式锁(以前抢红包需求,用了Redis分布式锁)
  • 状态机幂等

14. 多线程情况下,考虑线性安全问题

「高并发」情况下,HashMap可能会出现死循环。因为它是非线性安全的,可以考虑使用ConcurrentHashMap。所以这个也尽量养成习惯,不要上来反手就是一个new HashMap();

Hashmap、Arraylist、LinkedList、TreeMap等都是线性不安全的;Vector、Hashtable、ConcurrentHashMap等都是线性安全的

15. 使用缓存的时候,考虑缓存跟数据库的一致性,还有缓存穿透、缓存雪崩和缓存击穿问题

通俗点说,我们使用缓存就是为了「查得快,接口耗时小」。但是呢,用到缓存,就需要「注意缓存与数据库的一致性」问题。同时,还需要规避缓存穿透、缓存雪崩和缓存击穿三大问题。

缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。

缓存击穿:指热点 key 在某个时间点过期的时候,而恰好在这个时间点对这个 Key 有大量的并发请求过来,从而大量的请求打到db。

缓存雪崩:指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。

标签:缓存,15,代码,80%,数据库,线程,接口,考虑,bug
From: https://www.cnblogs.com/binbingg/p/17989728

相关文章

  • 面试经典 150题 (四)
    向前移动元素需要k的值,所以移动需要放在最后面。classSolution{publicintremoveDuplicates(int[]nums){if(nums.length<1)return0;intcurNum=nums[0];intk=0;intcount=0;inti;for(i=0;i......
  • webug4.0显错注入
    首先访问:http://192.168.195.139/control/sqlinject/manifest_error.php?id=1进入到这个靶场可以通过在url栏id=1处改数字、加单引号、#号、*号等等来判断注入点。如改成id=2,就会出现以下结果如果改成id=1)括号无反应,看来是屏蔽了id=1"双引号无反应id=1'单引号有结果,id=......
  • CF1515F Phoenix and Earthquake 题解
    题目链接:CF或者洛谷首先基于一个事实,答案一定是生成树,显然,每次我们都需要连边,每次都会\(-x\),那么一共会减少\((n-1)\timesx\),很显然的一个必要条件为:\[\sum_{i=1}^{n}a_i\ge(n-1)\timesx\显然一定成立。\]现在我们用来证明它同时也是一个充分条件,不妨设:\[a_1\lea......
  • P9805 [POI2022~2023R1] ply
    1st思路贪心当遇到左括号深度加一,可如果当前深度大于$H$时深度减二,并且$ans$加一。相当于进行一次翻转操作。当遇到右括号深度减一,当深度小于零时深度加二,并且$ans$加一。code#include<bits/stdc++.h>usingnamespacestd;strings;intk,n=0,m=0,ans=0;intmain......
  • P4159 [SCOI2009] 迷路 题解
    P4159[SCOI2009]迷路搬运工题目链接首先我们先考虑这道题的弱化版如何处理。假如所有的边权都是零和一。这时他们的边权可以看做这两个点走一步到达之间的方案数。而对于走t步,我们可以推出下列式子,\(f_{i,j}\)表示从节点\(i\)到节点\(j\)的方案数。\[f_{i,j}=\su......
  • CCF模拟_202312-2_因子化简(80%)
    计算机软件能力认证考试系统题目样例输入321558950643221000000000010Data样例输出2238728110000000000思路:这个题主要麻烦的地方应该在于分解成素数n次方相乘的数学思想和大整数的处理。关于素数分解,一个思路是简单粗暴地把小于n的所有素数都给尝试一遍(也......
  • solution-arc158e
    [ARC158E]AllPairShortestPaths还是挺牛逼的一题。但是为什么其他题解都说很板?看来还是我太菜了,见的题太少了。主要参考@TeneryTree首先考虑CDQ分治,只考虑处理\([l,mid]\)中的到\([mid+1,r]\)这些点的路径和。由于列数\(m=2\)所以我们考虑设\(f_{i,0/1}\)为左......
  • goland开启debug模式的修复
    1、使用下载的老版golandide工具,使用debug模式无法正常生效:异常信息是因为goland中的dlv.exe版本太老,也就是dlv.exe不能适配最新的go版本:errorlayer=debuggercouldnotpatchruntime.mallogc:notypeentryfound,use'types'foralistof2、处理方案:goinstallg......
  • [原创]Windows安装配置PostgreSql_15.5.1数据库
    [原创]Windows安装配置PostgreSql_15.5.1数据库   PostgreSql数据库有多种安装方式,windows上常用的是installer方式、binary手动安装方式,本文采用手动安装的方式处理。总体过程比较简单,有mysql配置经验的分分钟的事儿。    一、下载并解压文件到具体安装目录。 ......
  • P1504积木堡垒(简略)
    用DP枚举出每一个的能到达的高度,进行\(n\)次背包即可,\(ans[]\)记录高度\(j\)是否可行,高度\(j\)可行\(n\)次就是答案,\(j\)从\(maxn\)开始枚举//dp[i][j]表示前i个表示高度为j的存不存在//dp[i][j]=dp[i-1][j],dp[i][j]=dp[i-1][j-a[i]];选或者不选//顺序的话dp[j......