96SEO 2026-02-20 06:40 13
不知道大家有没有经历过维护一个已经离职的人的代码的痛苦一个方法写老长还有很多的if

根本无法阅读更不知道代码背后的含义最重要的是没有人可以问此时只能心里默默地问候这个留坑的兄弟。
。
其实造成这些原因的很大一部分原因是由于代码规范的问题如果写的规范注释好其实很多问题也就解决了。
所以本文我就从代码的编写规范格式的优化设计原则和一些常见的代码优化的技巧等方面总结了了45个小技巧分享给大家如果不足欢迎指正。
命名是写代码中最频繁的操作比如类、属性、方法、参数等。
好的名字应当能遵循以下几点
没有任何的实际意义没有体现出数量的意思所以我们应当指明数量的名称
在《代码整洁之道》这本书中作者提到了一个观点注释的恰当用法是用来弥补我们在用代码表达意图时的失败。
换句话说当无法通过读代码来了解代码所表达的意思的时候就需要用注释来说明。
作者之所以这么说是因为作者觉得随着时间的推移代码可能会变动如果不及时更新注释那么注释就容易产生误导偏离代码的实际意义。
而不及时更新注释的原因是程序员不喜欢写注释。
作者很懂啊
但是这不意味着可以不写注释当通过代码如果无法表达意思的时候就需要注释比如如下代码
catch代码有时会干扰我们阅读核心的代码逻辑这时就可以把try
整个方法非常长try中代码是真正的服务下线的代码实现finally可以保证读锁最终一定可以释放。
{read.lock();doInternalCancel(appName,
方法别太长就是字面的意思。
一旦代码太长给人的第一眼感觉就很复杂让人不想读下去同时方法太长的代码可能读起来容易让人摸不着头脑不知道哪一些代码是同一个业务的功能。
else判断我光理清代码思路就用了很久最终理清之后就用策略模式给重构了。
所以一旦方法过长可以尝试将相同业务功能的代码单独抽取一个方法最后在主方法中调用即可。
当一份代码重复出现在程序的多处地方就会造成程序又臭又长当这份代码的结构要修改时每一处出现这份代码的地方都得修改导致程序的扩展性很差。
所以一般遇到这种情况可以抽取成一个工具类还可以抽成一个公共的父类。
在有时我们平时写代码的情况可能会出现if条件套if的情况当if条件过多的时候可能会出现如下情况
{System.out.println(三友的java日记);}}}}
}System.out.println(三友的java日记);这样优化就感觉看起来更加直观
(((StringUtils.isBlank(person.getName())||
三友的java日记.equals(person.getName()))
汉.equals(person.getNational()))
}这段逻辑这种条件表达式乍一看不知道是什么仔细一看还是不知道是什么这时就可以这么优化
StringUtils.isBlank(person.getName())
三友的java日记.equals(person.getName());
汉.equals(person.getNational());if
当前端传递给后端参数的时候通常需要对参数进场检验一般可能会这么写
(StringUtils.isBlank(addPersonRequest.getName()))
(StringUtils.isBlank(addPersonRequest.getIdCardNo()))
}这种写虽然可以但是当字段的多的时候光校验就占据了很长的代码不够优雅。
针对参数校验这个问题有第三方库已经封装好了比如hibernate-validator框架只需要拿来用即可。
所以就在实体类上加NotBlank、NotNull注解来进行校验
}此时Controller接口就需要方法上就需要加上Valid注解
}不仅是给前端参数也包括提供给第三方的接口等这样接口调用方法可以按照固定的格式解析代码不用进行判断。
如果不一样相信我前端半夜都一定会来找你。
Spring中很多方法可以做到统一返回值而不用每个方法都返回比如基于AOP或者可以自定义HandlerMethodReturnValueHandler来实现统一返回值。
personService.selectById(personId);return
这个很好理解不传null值可以避免方法不支持为null入参时产生的空指针问题。
当然为了更好的表明该方法是不是可以传null值可以通过NonNull和Nullable注解来标记。
NonNull就表示不能传null值Nullable就是可以传null值。
{return;}personService.updateById(person);
{personService.updateById(person);
尽量不返回null值是为了减少调用者对返回值的为null判断如果无法避免返回null值可以通过返回Optional来代替null值。
Optional.ofNullable(personService.selectById(personId));
}如果不想这么写也可以通过NonNull和Nullable表示方法会不会返回null值。
日志内容太大不打印比如有时需要将图片转成Base64那么这个Base64就可以不用打印
在一个项目中可能会由于引入的依赖不同导致引入了很多相似功能的类库比如常见的json类库又或者是一些常用的工具类当遇到这种情况下应当规范在项目中到底应该使用什么类库而不是一会用Fastjson一会使用Gson。
(!CollectionUtils.isEmpty(persons))
就拿格式化日期来来说我们一般封装成一个工具类来调用比如如下代码
}这段代码看似没啥问题但是却忽略了SimpleDateFormat是个线程不安全的类所以这就会引起坑。
一般对于这种已经有开源的项目并且已经做得很好的时候比如Hutool就可以把轮子直接拿过来用了。
单一职责原则是设计模式的七大设计原则之一它的核心意思就是字面的意思一个类或者一个方法只做单一的功能。
就拿Nacos来说在Nacos1.x的版本中有这么一个接口HttpAgent
这个类只干了一件事那就是封装http请求参数向Nacos服务端发送请求接收响应这其实就是单一职责原则的体现。
当其它的地方需要向Nacos服务端发送请求时只需要通过这个接口的实现传入参数就可以发送请求了而不需要关心如何携带服务端鉴权参数、http请求参数如何组装等问题。
灵活性低。
java语言是单继承的无法同时继承很多类并且继承容易导致代码层次太深不易于维护
比如说OrderService需要使用UserService可以注入一个UserService而非通过继承UserService。
聚合和组合的区别就是组合是当对象一创建的时候就直接给属性赋值而聚合的方式可以通过set方式来设置。
比如说当你需要做一个可以根据不同的平台做不同消息推送的功能时就可以使用策略模式的方式来优化。
}最后提供一个方法当需要进行消息通知时调用notifyMessage传入相应的参数就行。
(messageNotifier.support(notifyType))
用好设计模式可以增加代码的扩展性但是滥用设计模式确是不可取的。
(StringUtils.isNotBlank(person.getName()))
{sb.append(姓名:).append(person.getName());}if
(StringUtils.isNotBlank(person.getIdCardNo()))
{sb.append(身份证号:).append(person.getIdCardNo());}//
省略System.out.println(sb.toString());
}比如上面打印Person信息的代码用if判断就能够做到效果你说我要不用责任链或者什么设计模式来优化一下吧没必要。
举个例子在实际项目中可能需要对一些图片进行存储但是存储的方式很多比如可以选择阿里云的OSS又或者是七牛云存储服务器等等。
所以对于存储图片这个功能来说这些具体的实现是可以相互替换的。
所以在项目中我们不应当在代码中耦合一个具体的实现而是可以提供一个存储接口
bytes);}如果选择了阿里云OSS作为存储服务器那么就可以基于OSS实现一个FileStorage在项目中哪里需要存储的时候只要实现注入这个接口就可以了。
fileStorage;假设用了一段时间之后发现阿里云的OSS比较贵此时想换成七牛云的那么此时只需要基于七牛云的接口实现FileStorage接口然后注入到IOC那么原有代码用到FileStorage根本不需要动实现轻松的替换。
随着时间的推移业务的增长有的代码可能不再适用或者有了更好的设计方式那么可以及时的重构业务代码。
就拿上面的消息通知为例在业务刚开始的时候可能只支持短信通知于是在代码中就直接耦合了短信通知的代码。
但是随着业务的增长逐渐需要支持app、邮件之类的通知那么此时就可以重构以前的代码抽出一个策略接口进行代码优化。
空指针是代码开发中的一个难题作为程序员的基本修改应该要防止空指针。
所以在需要这些的时候需要强制判断是否为null。
前面也提到可以使用Optional来优雅地进行null值判断。
pojo一般内部都有很多属性重写toString方法可以方便在打印或者测试的时候查看内部的属性。
(GUANG_DONG_PROVINCE.equals(province))
比如在使用一个api类锁或者进行IO操作的时候需要主动写代码需释放资源为了能够保证资源能够被真正释放那么就需要在finally中写代码保证资源释放。
如图所示就是CopyOnWriteArrayList的add方法的实现最终是在finally中进行锁的释放。
降低资源消耗。
通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度。
当任务到达时任务可以不需要的等到线程创建就能立即执行。
提高线程的可管理性。
线程是稀缺资源如果无限制的创建不仅会消耗系统资源还会降低系统
所以为了达到更好的利用资源提高响应速度就可以使用线程池的方式来代替手动创建线程。
如果对线程池不清楚的同学可以看一下这篇文章:7000字24张图带你彻底弄懂线程池
所以设置线程的名称可以帮助我们更好的知道代码是通过哪个线程执行的更容易排查问题。
在消费者在从服务端拉取消息的时候会单独开一个线程执行while循环只要stopped状态一直为false那么就会一直循环下去线程就一直会运行下去拉取消息。
当消费者客户端关闭的时候就会将stopped状态设置为true告诉拉取消息的线程需要停止了。
但是由于并发编程中存在可见性的问题所以虽然客户端关闭线程将stopped状态设置为true但是拉取消息的线程可能看不见不能及时感知到数据的修改还是认为stopped状态设置为false那么就还会运行下去。
针对这种可见性的问题java提供了一个volatile关键字来保证线程间的可见性。
加了volatile关键字之后一旦客户端的线程将stopped状态设置为true时候拉取消息的线程就能立马知道stopped已经是false了那么再次执行while条件判断的时候就不成立线程就运行结束了然后退出。
举个例子来说一般在调用第三方接口的时候可能会有一个鉴权的机制一般会携带一个请求头token参数过去而token也是调用第三方接口返回的一般这种token都会有个过期时间比如24小时。
我们一般会将token缓存到Redis中设置一个过期时间。
向第三方发送请求时会直接从缓存中查找但是当从Redis中获取不到token的时候我们都会重新请求token接口获取token然后再设置到缓存中。
假设当出现并发的时候同时来两个线程AB从缓存查找发现没有那么AB此时就会同时调用token获取接口。
假设A先获取到tokenB后获取到token但是由于CPU调度问题线程B虽然后获取到token但是先往Redis存数据而线程A后存覆盖了B请求的token。
这下就会出现大问题最新的token被覆盖了那么之后一定时间内token都是无效的接口就请求不通。
所以在实际中需要多考虑考虑业务是否有线程安全问题有集合读写安全问题那么就用线程安全的集合业务有安全的问题那么就可以通过加锁的手段来解决。
虽然在使用多线程可以帮助我们提高接口的响应速度但是也会带来很多问题。
一旦使用了异步就会导致两个线程不是同一个事务的导致异常之后无法正常回滚数据。
之前有个小伙伴遇到需要同时处理几万调数据的需求每条数据都需要调用很多次接口为了达到老板期望的时间要求使用了多线程跑开了很多线程此时会发现系统的cpu会飙升
还是上面的提到的例子在测试的时候就发现由于并发量激增在请求第三方接口的时候返回了很多错误信息导致有的数据没有处理成功。
虽然说慎用异步但不代表不用如果可以保证事务的问题或是CPU负载不会高的话那么还是可以使用的。
减小锁的范围就是给需要加锁的代码加锁不需要加锁的代码不要加锁。
这样就能减少加锁的时间从而可以较少锁互斥的时间提高效率。
比如CopyOnWriteArrayList的addAll方法的实现lock.lock();
代码完全可以放到代码的第一行但是作者并没有因为前面判断的代码不会有线程安全的问题不放到加锁代码中可以减少锁抢占和占有的时间。
比如在项目中不同的类型的业务可能需要上传各种各样的附件此时就可以定义好不同的一个附件的枚举来区分不同业务的附件。
不要在代码中直接写死不定义枚举代码阅读起来非常困难直接看到数字都是懵逼的。
。
比如在进行微服务之间进行rpc调用的时候又或者在调用第三方提供的接口的时候需要设置超时时间防止因为各种原因导致线程”卡死“在那。
我以前就遇到过线上就遇到过这种问题。
当时的业务是订阅kafka的消息然后向第三方上传数据。
在某个周末突然就接到电话说数据无法上传了通过排查线上的服务器才发现所有的线程都线程”卡死“了最后定位到代码才发现原来是没有设置超时时间。
比如在写代码的时候经常会用到List、Map来临时存储数据其中最常用的就是ArrayList和HashMap。
但是用不好可能也会导致性能的问题。
比如说在ArrayList中底层是基于数组来存储的数组是一旦确定大小是无法再改变容量的。
但不断的往ArrayList中存储数据的时候总有那么一刻会导致数组的容量满了无法再存储其它元素此时就需要对数组扩容。
所谓的扩容就是新创建一个容量是原来1.5倍的数组将原有的数据给拷贝到新的数组上然后用新的数组替代原来的数组。
在扩容的过程中由于涉及到数组的拷贝就会导致性能消耗同时HashMap也会由于扩容的问题消耗性能。
所以在使用这类集合时可以在构造的时候指定集合的容量大小。
在开发中经常需要对JavaBean进行转换但是又不想一个一个手动set比较麻烦所以一般会使用属性拷贝的一些工具比如说Spring提供的BeanUtils来拷贝。
不得不说使用BeanUtils来拷贝属性是真的舒服使用一行代码可以代替几行甚至十几行代码我也喜欢用。
但是喜欢归喜欢但是会带来性能问题因为底层是通过反射来的拷贝属性的所以尽量不要用BeanUtils来拷贝属性。
比如你可以装个JavaBean转换的插件帮你自动生成转换代码又或者可以使用性能更高的MapStruct来进行JavaBean转换MapStruct底层是通过调用settter/getter来实现的而不是反射来快速执行。
拼接字符串的时候会创建一个StringBuilder然后将要拼接的字符串追加到StringBuilder再toString这样如果多次拼接就会执行很多次的创建StringBuilderz执行toString的操作。
所以可以手动通过StringBuilder拼接这样只会创建一次StringBuilder效率更高。
sb.append(123).append(456).append(789).toString();39、Transactional应指定回滚的异常类型
平时在写代码的时候需要通过rollbackFor显示指定需要对什么异常回滚原因在这
默认是只能回滚RuntimeException和Error异常所以需要手动指定比如指定成Expection等。
处理updatePerson(person);}Transactional(rollbackFor
处理}}update调用了加了Transactional注解的updatePerson方法那么此时updatePerson的事务就是失效。
其实失效的原因不是事务的锅是由AOP机制决定的因为事务是基于AOP实现的。
AOP是基于对象的代理当内部方法调用时走的不是动态代理对象的方法而是原有对象的方法调用如此就走不到动态代理的代码就会失效了。
处理personService.updatePerson(person);}Transactional(rollbackFor
比如有些文本的字段存储的数据非常长但是本次业务使用不到但是如果查了就会把这个数据返回给客户端增加了网络传输的负担
比如说现在有身份证号和姓名做了联合索引现在只需要根据身份证号查询姓名如果直接select
的话那么在遍历索引的时候发现要查询的字段在索引中已经存在那么此时就会直接从索引中将name字段的数据查出来返回而不会继续去查找聚簇索引减少回表的操作。
所以建议是需要使用什么字段查询什么字段。
比如mp也支持在构建查询条件的时候查询某个具体的字段。
Wrappers.query().select(name);42、不循环调用数据库
比如需要查询一批人员的信息人员的信息存在基本信息表和扩展表中错误的代码如下
ArrayList(personIds.size());ListPerson
personMapper.selectByIds(personIds);for
personExtMapper.selectById(person.getId());//
ArrayList(personIds.size());ListPerson
personMapper.selectByIds(personIds);//批量查询转换成MapListPersonExt
personExtMapper.selectByIds(person.getId());MapString,
personExtList.stream().collect(Collectors.toMap(PersonExt::getPersonId,
PersonVO();//直接从Map中查找PersonExt
personExtMap.get(person.getId());//
如上面代码所示原本也可以将两张表根据人员的id进行关联查询。
但是不推荐这么阿里也禁止多表join的操作
MySQL是使用了嵌套循环的方式来实现关联查询的也就是for循环会套for循环的意思。
用第一张表做外循环第二张表做内循环外循环的每一条记录跟内循环中的记录作比较符合条件的就输出这种效率肯定低。
我们平时写代码由于各种因为比如什么领导啊项目经理啊会一直催进度导致写代码都来不及思考怎么快怎么来cv大法上线虽然有心想写好代码但是手确不听使唤。
所以我建议装一个阿里的代码规范插件如果有代码不规范会有提醒这样就可以知道哪些是可以优化的了。
写代码的时候不能闭门造车及时跟同事沟通比如刚进入一个新的项目的对项目工程不熟悉一些技术方案不了解如果上来就直接写代码很有可能就会踩坑。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback