Java开发的一些编码建议
1、无论是类、方法、字段、变量,尽可能的限制他们的作用范围,可以避免出现不必要的错误;同时虚拟机也能有更大的优化空间。
2、错误越早发现越好,编译时发生错误比在运行时发生错误好。而且编译时错误能更好的定位问题所在。
这两条建议来源于阅读《Effective Java》后的总结。
书中第15条:使类和成员的可访问性最小化以及第16条:要在公有类中使用访问方法而非公有域大部分使用Spring开发的人都会这么去做,但是我觉得大部分的初级开发甚至是中级开发者并不知道为什么要这么做,只不过是在依葫芦画瓢。
一个设计良好的类除了要满足高内聚、低耦合之外应当还要具备良好的封装性。以常用的ArrayList举例,在idea中进行编码时输入"list."之后idea就会列出add、set等方法,但是不会出现grow等实现细节所需的方法,即使自己拼出来方法名也无法通过编译。
试想一下,倘若一个类只提供两个客户端所需要的方法,然后有很多实现细节所需的方法,但是这些方法并没有封装。后果就是不熟悉这个类的人需要去看所有方法的注释或者源码,这对使用该类的开发人员是一种极其不好的体验,而且还可能因为疏忽调用错方法导致程序没有按照开发者所预想的逻辑进行,但是这个错误无法在编译时发现,如果测试用例正好没覆盖到此处,那么这个错误可能在某一天对系统产生重大的影响。开发者所能做的就是尽可能的把错误扼杀在摇篮。
至于第十六条估计没有Java开发者不遵守,在编写实体类时字段都为private,然后通过getter、setter方法去获取与修改。初学Java时觉得这种做法跟脱裤子放屁一样多此一举。
现在才明白字段field权限为public那将意味着这个类失去了对该字段的控制。试想如果field为int类型,但是类的设计者希望field的大小只在1-10之间,那设计者只能在每次使用field时进行校验(因为要把使用者当傻子,不能指望他能按照预期进行输入),如果field是在多处使用,代码看上去很臃肿,并且容易在某个地方遗漏,特别是其他开发者进行维护时。field权限为private就没这么多事了,因为在setter时可以直接校验。
第40条:坚持使用Override注解
@Override注解都知道是覆盖超类方法用的,但是不加其实也能覆盖,程序不会出现任何问题,那么他的意义在哪呢?请看以下代码
public class Bigram {private final char first;private final char second;public Bigram(char first, char second){this.first = first;this.second = second;}public boolean equals(Bigram b){return b.first == first && b.second == second;}public int hashCode(){return 31 * first + second;}public static void main(String[] args) {Set<Bigram> s = new HashSet<>();for (int i = 0; i < 10; i++) {for (char ch = 'a'; ch <= 'z'; ch++) {s.add(new Bigram(ch,ch));}}System.out.println(s.size());}
}
代码意图很明显,往一个Set中添加a,a、b,b…z,z的实例对象,由于Set会去重,所以无论循环多少次按理说打印结果都是26,我阅读此处时也觉得是26,然而结果是260。
原因就是我们以为Bigram类覆盖了Object的equals,但其实是重载了,因为Object的equals方法形参是Object,而Bigram的形参是Bigram。
这种没有任何异常的逻辑错误,如果系统有一定的规模,排查的时候可以说是有不小难度的。如果在equals方法上加上@Override注解那么在编译时就能够提醒此处有问题,无法编译通过,能够很好的避免此类bug。
第49条:检查参数的有效性
很多方法或者构造器对于传递给它们的参数值都会有某些限制。最常见的限制有索引必须是非负数,对象引用不能为null等。这些限制应当在方法体开头处检查,尽早的发现错误。如果不对参数进行检查可能会发生以下三种情况:
1、抛出异常
2、方法正常返回,但是结果是错误的
3、破坏了某个对象的状态
如果是第一种情况其实还好,起码能通过堆栈信息发现错误。如果是第二或者第三种情况,在程序运行时是难以发现的,可能在某个时候对公司造成不可预估的损失。
假设有以下业务:系统统计班级捐款金额。
public class Donation {private int sum = 0;public void add(int money) {sum += money;}public int getSum() {return sum;}
}
当某个同学不小心输入了一个“-”,那么这样的bug是难以发现的,毕竟一两个人的捐款金额相对于一整个班级而言影响比较有限。
第57条:将局部变量的作用域最小化
最有力的例子就是for循环优于while循环
Iterator<Element> i = c.iterator;
while (i.hasNext()){doSomething(i.next());
}
....
Iterator<Element> i2 = c.iterator;
while (i.hasNext()){ //BUG,但是编译可以通过doSomething(i2.next());
}for (Iterator<Element> i = c.iterator;i.hasNext();){doSomething(i.next());
}
...
//编译无法通过,i的作用域只在上一个循环体中
for (Iterator<Element> i2 = c.iterator;i.hasNext();){doSomething(i2.next());
}
别说不会犯这种错误,复制粘贴多了总会有犯错的情况。(如果只是遍历读取的情况,for-each比for循环更合适,但是与本篇博客的两个总结点无关,所以没有写)
结语
为什么不按照《Effective Java》的排版进行总结?
因为有些内容还没理解透彻,再加上这些内容可能在实际开发中更常用,这些内容的思想非常值得学习。还有一个原因就是在阅读《深入理解Java虚拟机》时学习了逃逸分析的相关内容,如果某个变量所引用的对象作用范围仅在当前方法,可能JVM会对其进行优化,该对象实例的内存不一定在堆中,可能是栈上分配,然后随着方法执行结束回收内存,能够有效的降低垃圾回收的运行,提高系统的性能。
可能《Effective Java》中还有其他条目也是这两种思想。但是阅读时间线比较长,以及有些部分还没阅读,可能会遗漏某些条目,发现了再补上。
相关文章:
Java开发的一些编码建议
1、无论是类、方法、字段、变量,尽可能的限制他们的作用范围,可以避免出现不必要的错误;同时虚拟机也能有更大的优化空间。 2、错误越早发现越好,编译时发生错误比在运行时发生错误好。而且编译时错误能更好的定位问题所在。 这…...
【YOLOv8/YOLOv7/YOLOv5/YOLOv4/Faster-rcnn系列算法改进NO.59】引入ASPP模块
前言作为当前先进的深度学习目标检测算法YOLOv8,已经集合了大量的trick,但是还是有提高和改进的空间,针对具体应用场景下的检测难点,可以不同的改进方法。此后的系列文章,将重点对YOLOv8的如何改进进行详细的介绍&…...
C++STL set/multiset容器 构造和赋值 大小和交换 插入和删除 查找和统计
文章目录set/multiset容器1 set容器 基本概念2 set容器 构造和赋值3 set容器 大小和交换4 set容器 插入和删除5 set容器 查找和统计set/multiset容器 1 set容器 基本概念 简介: 所有元素都会在插入时会被自动排序,例如,在set容器放入元素1、…...
产品研发项目进度管理软件工具有哪些推荐?整理10款最佳进度管理软件
项目进度管理是确保项目按时完成的关键过程,使用合适的项目进度管理工具能确保帮助项目管理者实时了解和控制项目的进展情况,及时发现和解决问题,减少项目风险,提高项目效率和管理水平。这里将整理出国内外最受欢迎的10款项目进度…...
「ML 实践篇」分类系统:图片数字识别
目的:使用 MNIST 数据集,建立数字图像识别模型,识别任意图像中的数字; 文章目录1. 数据准备(MNIST)2. 二元分类器(SGD)3. 性能测试1. 交叉验证2. 混淆矩阵3. 查准率与查全率4. P-R 曲…...
从大专到测开,上海某字母站大厂的面试题,岗位是测开(25K*16)
简单介绍一句,大专出身,三年经验。跳了四次槽,面试了无数次,现在把自己的面试经验整理出来分享给大家,堪称必杀技! 1,一切从实际出发,对实际工作进行适当修饰 2,不会的简…...
【面试题】Python软件工程师能力评估试题(一)
文章目录前言应试者需知(一)Python 语言基础能力评估1、理解问题并完成代码:2、阅读理解代码,并在空白处补充完整代码:3、编写一个装饰器:exposer4、阅读代码并在空白处补充完整代码:5、自行用P…...
Java八股文(Java多线程面试题)
并行和并发的区别?(1)并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生;(2)并行是在不同实体上的多个事件,并发是在同一实体上的多个事件&#…...
小程序当前页面如何分享别的页面内容呢?
需求分析 因为功能的需要分为两点 他需要调转转发,并且有首页转发点击button按钮进行转发邀请好友帮忙助力,如何做到一个页面多种转发 如何区分,是button转发还剩右上角三个点转发呢? 通过onShareAppMessage()这个函数的事件…...
编写Java哪个编译器好
现在能够编写Java代码的工具简直不要太多,各种各样五花八门,但目前效率最高的还是Intellij Idea。但这个工具对于完全零基础的小白来说,第一次用起来是比较复杂的,因为它的功能太多了。这就好比你要学开车,如果上来就给…...
第十六章 Java为什么使用序列化
为何要指定serialVersionUID的值如果不指定显示serialVersionUID的值,jvm在序列化时会自动生成一个serialVersionUID,跟属性一起序列化,再进行持久化或者网络传输,在反序列化时,jvm会根据属性自动生成一个新版的serial…...
28岁小公司程序员,无车无房不敢结婚,要不要转行?
大家好,这里是程序员晚枫,又来分享程序员的职场故事了~ 今天分享的这位朋友叫小青,我认识他2年多了。以前从事的是土木行业,2年前找我咨询转行程序员的学习路线和职业规划后,通过自学加入了一家创业公司,成…...
出道即封神的ChatGPT,现在怎么样了?
从互联网的普及到智能手机,都让广袤的世界触手而及,如今身在浪潮中的我们,已深知其力。前阵子爆火的ChatGPT,不少人保持观望态度。现如今,国内关于ChatGPT的各大社群讨论,似乎沉寂了不少,现在怎…...
【计算机视觉】CNN 可视化算法
文章目录一、CAM算法1.1 概述1.2 CAM算法介绍二、Grad-CAM算法2.1 概述2.2 Guided Backpropagation2.3 Occlusion Sensitivity2.4 Grad-CAM 整体结构和效果2.5 Grad-CAM 实现细节一、CAM算法 1.1 概述 本文介绍 2016 年提出的 CAM (Class Activation Mapping) 算法࿰…...
自动抓取服务器巡检、登录、执行命令记录+备份脚本
文章目录 引抓取【巡检日志】语言&时区设置语言设置时区巡检脚本执行效果抓取【登录信息】登录脚本登录脚本低版本的last命令执行效果抓取【history记录】说明配置history授权日志文件显示时间戳持久化到日志未配置history的配置过history的执行脚本执行脚本...
如何用Python求解微分方程组
文章目录odeint简介示例odeint简介 scipy文档中将odeint函数和ode, comples_ode这两个类称为旧API,是scipy早期使用的微分方程求解器,但由于是Fortran实现的,尽管使用起来并不方便,但速度没得说,所以有的时候还挺推荐…...
【微信小程序】-- 自定义组件 - behaviors(三十九)
💌 所属专栏:【微信小程序开发教程】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…...
【微信小程序】-- 自定义组件 - 父子组件之间的通信(三十八)
💌 所属专栏:【微信小程序开发教程】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…...
Java Web 实战 11 - 多线程进阶之常见的锁策略
常见的锁策略常见的锁策略1. 乐观锁 VS 悲观锁2. 普通的互斥锁 VS 读写锁3. 重量级锁 VS 轻量级锁4. 自旋锁 VS 挂起等待锁5. 公平锁 VS 非公平锁6. 可重入锁 vs 不可重入锁7. 常见面试题大家好 , 这篇文章给大家带来的是多线程中常见的锁策略 , 我们会给大家讲解 6 种类别的锁…...
(20)目标检测算法之YOLOv5计算预选框、详解anchor计算
目标检测算法之YOLOv5计算预选框、详解anchor计算 单节段目标检测算法中:预选框的设定直接影响最终的检测精度众所周知,yolov5中采用自适应调整预选框anchor的大小,但万事开头难,配置文件config中的预设还是很重要yolo算法作为on…...
Memos笔记数据安全吗?手把手教你配置自动备份到GitHub/对象存储(防丢指南)
Memos数据安全全攻略:从本地备份到云端同步的完整方案 Memos作为一款轻量级开源笔记工具,凭借其简洁界面和本地存储特性赢得了不少用户青睐。但数据安全始终是悬在每位用户心头的一把剑——服务器宕机、硬盘损坏、误操作删除都可能让珍贵笔记瞬间消失。本…...
别再手动点灯了!用Simulink串口实时控制STM32,5分钟搞定双向通信
基于Simulink与STM32的实时双向通信实战指南 在嵌入式系统开发中,快速原型验证是提升效率的关键环节。传统开发模式下,工程师需要花费大量时间编写底层通信协议、调试硬件接口,而真正核心的控制算法验证反而被边缘化。本文将介绍一种高效开发…...
别再为GPU发愁了!手把手教你用Kaggle免费GPU跑YOLOv7(附完整避坑清单)
零成本玩转YOLOv7:Kaggle GPU资源深度优化指南 当我在大学实验室第一次尝试训练YOLOv7模型时,那台老旧的GTX 1060显卡发出的轰鸣声至今难忘。36小时后,它终于完成了1/3的训练进度——这个经历让我深刻理解到,对于大多数个人开发者…...
重构macOS鼠标体验:从痛点到解决方案的技术探索
重构macOS鼠标体验:从痛点到解决方案的技术探索 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix 【问题发现:被忽视的交互…...
PyTorch 2.8镜像代码实例:使用预装torchaudio+FFmpeg实现TTS+视频合成Pipeline
PyTorch 2.8镜像代码实例:使用预装torchaudioFFmpeg实现TTS视频合成Pipeline 1. 环境准备与快速验证 在开始之前,我们先确认环境是否正常工作。这个PyTorch 2.8镜像已经预装了所有必要的组件,包括torchaudio和FFmpeg。 1.1 验证GPU可用性 …...
Asp.Net MVC杂谈之:—步步打造表单验证框架[重排版](1)
在实际使用中,我们可以考虑多种形式来进行这一验证(注:本文目前只研究服务器端验证的情况),最直接的方式莫过于对每个表单值手动用C#代码进行验证了,比如: if(!Int32.TryParse(Request.Form[“age”], out age)){ xxxx… } If(age < xxx || age > xxx){ xxxx… }…...
告别杀后台!深度评测Ba-KeepAlive-U:这款UniAppX安卓保活插件到底有多强?(附多机型测试结果)
Ba-KeepAlive-U技术解析:如何为UniAppX应用实现跨机型保活方案 在移动应用开发领域,后台进程存活率一直是困扰开发者的技术难题。尤其对于需要持续运行定位、即时通讯或数据同步功能的应用,系统资源管理策略导致的"杀后台"现象直接…...
Z-Image-Turbo LoRA WebUI实战案例:为独立游戏开发者生成角色立绘素材
Z-Image-Turbo LoRA WebUI实战案例:为独立游戏开发者生成角色立绘素材 1. 项目概述与价值 作为一名独立游戏开发者,你是否曾经为角色立绘的设计而头疼?传统的美术外包成本高昂,自己绘制又需要专业技能。现在,通过Z-I…...
TensorFlow实战:用CIFAR-10数据集训练你的第一个图像分类模型(附完整代码)
TensorFlow图像分类实战:从零构建CIFAR-10卷积神经网络的完整指南 当第一次接触图像分类任务时,许多开发者会被复杂的网络结构和数据处理流程所困扰。本文将带你用TensorFlow构建一个能识别10类常见物体的卷积神经网络,从数据加载到模型评估&…...
告别天价桥接芯片!用高云GW5AT-LV15MG132 FPGA搞定MIPI C-PHY摄像头测试盒
国产FPGA革新摄像头测试方案:高云GW5AT-LV15MG132的MIPI C-PHY实战解析 在摄像头模组生产线上,测试环节的成本与效率直接关系到企业竞争力。传统测试方案依赖进口FPGA搭配昂贵桥接芯片,不仅物料清单(BOM)成本居高不下…...
