一、序言
代码是给程序员看的,不是给领导看的,也不是给客户看的,更不是给女朋友看的!
如果你想成为一名优秀的程序员,那么,整洁代码之道这本书,我感觉一般吧,哈哈
怎么说呢,读完本书,对怎么写好代码有了一个直观的认识,但,如果说读完本书,就能成为一名优秀的程序员,我感觉有点扯
如果你是一名至少有1W+行以上的代码工作者的话,本书可以跳着看,具体到某些地方时,可以细细品味
如果你是一个新手的话,不建议看,因为全篇多半是围绕着代码讲的,其中涉及实际开发工作中的多个需要注意的地方,对你来说,文字都抽象的不行了,别说让你看代码了;怎么办,先把代码量码起来了再回头看这本书,你会别有一番感慨!
话又说回来,如何成为一个优秀的程序员呢?
不想当将军的士兵不是好士兵,程序员也一样,我们不可能写一辈子代码吧,而且代码也不可能陪我们一辈子【更新换代太快】
要想摆脱写代码,首先你得把代码这件事情干好,如何干好:多学,多做,多写,多读,多思考!
先把程序员的工作干好,然后再往管理层上爬,试想一下,如果你自己连代码都写不好,怎么让手底下的程序员服服帖帖呢?
【关于本书的靓点,我会持续更新在本篇博文中!】
百度网盘下载地址:https://pan.baidu.com/s/1o6yHxzrC-WDlStTAwKQ2GA
一、命名:
(1)命名要有意义,不要太随性,给变量或方法起个毫不相干的名称,或者起个名称,让人完全猜不出其表达的是什么
private String n;
================
private String name;
(2)使用便于搜索的名称【正常一周工作5天,明显第二个命名要比第一个要好,因为它相比数字5来说更容易搜索且更有意义】
private final Integer DAYS= 5;
=================================
private final Integer WORK_DAYS_PEER_WEEKS = 5;
(3)....后续有时间再补充
二、函数:
(1)专注干一件事情,不要在一个函数里面干大量的事,如果有,尽量拆分成多个函数
(2)尽量不要让函数的参数过多,一个参数的函数要比两个参数的函数更好的去理解和使用,参数一多,使用者就短暂懵逼了
(3)函数里面的代码不要过多,函数要尽量"短小精悍"、"一击致命"...etc【超过80行的代码,我就有点看不下去了】
(4)...后续有时间再补充
三、注释:
(1)注释就是一个错误,能用代码表达意图的,尽量不要用注释,只有让人看不懂的地方才会加以注释说明
(2)不要把注释当做是一个故事在阐述,你会让其他程序员在阅读你代码的时候抓头发、飙脏话的 "与我何干?"
(3)不要为了符合javadoc的风格而去注释,比如,下面的注释简直就是毫无意义
public class User{
/**
* 用户的名称
*/
private String name;
}
(4)....后续有时间再补充
四、格式:
(1)紧密相关的代码行应该互相靠近
(2)变量的定义应该放在类的顶部
(3)概念相关的代码应该放在一起,相关性越强,距离越短
(4)被调用的函数应该放在调用它的函数的下面,符合人们从上至下扫代码的习惯
(5)单行代码的宽度【字符长度控制在120之内】不要过长,否则让人看着会不舒服
(6)空格字符可以将紧密相关的事物连接到一起,也可以将弱相关的事物隔开,比如强调运算符
int a+=1;
int a += 1;
(7)慎用代码对齐【工具会消除自定义的对齐格式】,这会使我们忽略掉变量的类型或者一些运算符,看着怪怪的
private Socket socket ;
private InputStream iStream;
private ResponseResult result ;
private Char ch ;
private String content;
=================================
this.socket = socket;
iStream = new FileInputStream(path);
ch = 'a';
content += ch.ToString();
(8)必要的地方【如变量、方法块、if..else块...etc】加缩进,不要让代码看起来邋遢不堪
public class User{
private String name;
private Integer age;
public User(String name,Integer age){
this.name = name;
this.age = age;
}
}
==========================
public class User{
private String name;
private Integer age;
public User(String name,Integer age){
this.name = name;
this.age = age;
}
}
(9)...后续有时间再补充
五、对象和数据结构:
(1)过程式代码(使用数据结构的代码)便于在不改变既有数据结构(单一类,无行为)的前提下添加新函数
但是,过程式代码却难于添加新的数据结构,因为它要修改所有和数据结构有关的函数
// 几何形状 -- 正方形
public class Square{
// 边
public double side ;
}
// 几何形状 -- 长方形
public class Rectangle{
// 长
public double height;
// 宽
public double width;
}
// 几何形状 -- 圆形
public class Circle{
// 半径
public double radius;
}
// 几何类 -- 几何的操作放在该类中
public class Geometry{
public double getArea(Object shape) {
// 伪代码
if(shape instanceof 正方形){
Square square = (Square)shape ;
return square .side * square .side ;
}else if(shape instanceof 长方形){
return 长*宽 ;
}else if(shape instanceof 圆形){
return PI*半径*半径 ;
}
}
}
上述代码就好比一个过程式代码:三个形态类都是单一的数据结构,没有操作,操作全部放在Geometry类中实现
好处就是:在Geometry中添加新的方法,比如计算周长【getPerimeter】方法时,不会影响到既有的数据结构(三个形状类),直接在方法里面写dosomething即可;
反之,则比较麻烦,如果我又增加了一个椭圆形状【ellipse】,即又增加了一个数据结构,试想一下,Geometry类中是不是所有和数据结构有关的函数都要修改,比如,计算面积和计算周长的方法里面,是不是都要新增有关椭圆的实现demo呢
(2)面向对象代码便于在不改既有函数的前提下添加新类
但是,面向对象代码却难于添加新函数,因为会涉及到所有类的修改
// 形状接口
public interface Shape{
// 计算面积
double getArea();
// 计算周长
double getperimeter();
}
// 几何形状 -- 正方形
public class Square implements Shape{
// 边
public double side ;
@Override
public double getArea() {
return side*side;
}
@Override
public double getperimeter() {
return 4*side;
}
}
// 几何形状 -- 长方形
public class Rectangle implements Shape{
// 长
public double height;
// 宽
public double width;
@Override
public double getArea() {
return height*width;
}
@Override
public double getperimeter() {
return (height+width)*2;
}
}
// 几何形状 -- 圆形
public class Circle implements Shape{
// 半径
public double radius;
@Override
public double getArea() {
return Math.PI*radius*radius;
}
@Override
public double getperimeter() {
return 2*Math.PI*radius;
}
}
上述代码利用面向对象的多态特性,实现了三种不同形状的面积和周长的计算【实现形状接口】
【多态:同一个实体同时具有多种表现形式】
好处:在不添加新函数时,很容易添加新类,如再添加一个椭圆(eclipse)实现shape接口即可,不会影响到既有函数
反之:如果添加新的函数,就不得不改变既有类的所有方法了【接口中定义的方法,实现类中必须实现】
(3)总结:对于过程式代码不容易干的事情,面向对象很容易搞定,反之亦然!
【好好思考一下上面的话,在项目中应该如何拿捏,什么时候用谁? 还真不是一件简单的事情!】
(4)...有时间再补充
六、错误处理
(1)拿捏好不可控异常和可控异常的使用,建议使用不可控异常,因为可控异常,粘合度太高,牵一发动全身
【可控异常就是自己写的代码造成的异常,自己犯的错需要自己去改正,如果不处理就是bug】
(2)对抛出的每一个异常做充分的环境说明,标记此次异常发生的出处和原因
(3)依据调用者的需要自定义异常类
public class MyException extends Exception{
private static final long serialVersionUID = 1636053543616552109L;
private Integer errorCode;
public MyException(String message) {
super(message);
}
public Integer getErrorCode() {
return errorCode;
}
public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
}
(4)避免返回和传递null值,避开让人厌烦的NullPointerException
/**
* 验证名称列表
*/
public void validateNames(){
List<String> names = getNames();
if(names!=null && names.size() > 0){
for (String name : names) {
System.out.println("name : "+name);
}
}
}
/**
* 获取名称列表
*/
public List<String> getNames(){
return userMapper.getUserNames();
}
================================================
public void validateNames(){
List<String> names = getNames();
for (String name : names) {
System.out.println("name : "+name);
}
}
public List<String> getNames(){
List<String> names = userMapper.getUserNames();
// 在dao层就对names做一个null值的判断,而不是把它放在调用者调用它的地方
if(names == null || names.size() == 0){
return Collections.emptyList();
}
return names;
}