编写高效优雅的Java程序

1.面向对象

1.1 构造器参数太多怎么办?

FoodNormal.java
对于多个成员变量的类构造函数,对于不同参数个数的构造函数一般需要定义多个构造函数,比较麻烦。

FoodJavaBean.java
对于JavaBean模式,使用set/get方式可能会使得得到的对象,某个成员变量没有初始化就使用了该成员变量,会有问题。

FoodBuilder.java
比较好的初始化方式是用Builder构造者模式。初始化直接采用链式初始化的方式进行初始化。

用builder模式,用在
1、5个或者5个以上的成员变量
2、参数不多,但是在未来,参数会增加

Builder模式:
builder模式参考代码
属于对象的创建模式,一般有
1、 抽象建造者:一般来说是个接口,包含
 1)建造方法,建造部件的方法(不止一个)
 2)返回产品的方法
2、 具体建造者
3、 导演者,调用具体的建造者,创建产品对象
4、 产品,需要建造的复杂对象
对于客户端(Mingyun.java),创建导演者和具体建造者,并把具体建造者交给导演者,然后由客户端通知导演者操纵建造者进行产品的创建。
在实际的应用过程中,有时会省略抽象建造者和导演者。

1.2 不需要实例化的类应该构造器私有

一些工具类提供的都是静态方法,这些类是不应该提供具体的实例的。可以参考JDK中的Arrays。

1.3 不要创建不必要的对象

1、 避免无意中创建的对象,如自动装箱


2、 可以在类的多个实例之间重用的成员变量,尽量使用static。



修改为如下,只创建一次,对象间共享:

    private static final Date Begin;
    //private static final Date End;
    
    static {
        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        cal.set(1990, Calendar.JANUARY,1,0,0,0);
        Begin = cal.getTime();
        //.....
    }

但是,要记住,是不要创建不必要的对象,而不是不要创建对象。
对象池要谨慎使用,除非创建的对象是非常昂贵的操作,如数据库的连接,巨型对象等等。

1.4 避免使用终结方法

finalizer方法,jdk不能保证何时执行,也不能保证一定会执行。如果有确实要释放的资源应该用try/finally。

1.5 使类和成员的可访问性最小化

编写程序和设计架构,最重要的目标之一就是模块之间的解耦。使类和成员的可访问性最小化无疑是有效的途径之一。

1.6 使可变性最小化

尽量使类不可变,不可变的类比可变的类更加易于设计、实现和使用,而且更不容易出错,更安全。
常用的手段:
不提供任何可以修改对象状态的方法;
使所有的域都是final的。
使所有的域都是私有的。
使用写时复制机制。带来的问题:会导致系统产生大量的对象,而且性能有一定的影响,需要在使用过程中小心权衡。

1.7 优先使用复合

继承容易破坏封装性,而且会使子类的实现依赖于父类。
复合则是在类中增加一个私有域,引用类的一个实例,这样的话就避免了依赖类的具体实现。
只有在子类确实是父类的一个子类型时,才比较适合用继承。

1.8 接口优于抽象类

java是个单继承的,但是类允许实现多个接口。
所以当发生业务变化时,新增接口,并且需要进行业务变化的类现新接口即可。但是抽象类有可能导致不需要变化的类也不得不实现新增的业务方法。
在JDK里常用的一种设计方法是:定义一个接口,声明一个抽象的骨架类实现接口,骨架类类实现通用的方法,而实际的业务类可以同时实现接口又继承骨架类,也可以只实现接口。
如HashSet实现了implements Set接口 但是又extends 类AbstractSet,而AbstractSet本身也实现了Set接口。其他如Map,List都是这样的设计的。

2.方法

2.1 可变参数要谨慎使用

可变参数是允许传0个参数的
如果是参数个数在1~多个之间的时候,要做单独的业务控制。

    //可能很多 0~很多
    static int sum(int... args) {
        int sum = 0;
        for (int arg : args)
            sum += arg;
        return sum;
    }
    
    //要求参数的个数,是1~多个
    //
    static int sum1(int... args) {
        if(args.length==0) {
            //做点异常处理
        }
        if(args[0]==100) {

        }
        for(int i=1;i<args.length;i++) {
            int sum = 0;
            sum += args[i];
            return sum; 
        }
    }

    static int sum2(int flag, int... args) {
        if(flag==100) {

        }
        int sum = 0;
        for (int arg : args)
            sum += arg;
        return sum;
        return Collections.EMPTY_LIST;
    }

2.2 返回零长度的数组或集合,不要返回null

方法的结果返回null,会导致调用方的要单独处理为null的情况。返回零长度,调用方可以统一处理,如使用foreach即可。
JDK中也为我们提供了Collections.EMPTY_LIST这样的零长度集合

2.3 优先使用标准的异常

要尽量追求代码的重用,同时减少类加载的数目,提高类装载的性能。
常用的异常:
IlegalAraumentException -- 调用者传递的参数不合适
lllegalStateException – 接收的对象状态不对,
NullPoint
UnsupportedOperationException –不支持的操作

3.通用程序设计

3.1 用枚举代替int常量

声明的一个枚举本质就是一个类,每个具体的枚举值就是这个枚举类的实例。
SampleIntConst.java
常量会带来一些小问题,所以优先使用枚举:

  • 1)常量传播导致的修改不一致问题
  • 2)常量值修改变动的问题
  • 3)打印时,需要配套一个字符串说明

DepotEnum.java
枚举实际上是类,可以定义自己的方法和成员变量。

ActiveEnum.java
对于算术运算类型的枚举类,相比于使用switch来区分,可以定义一个oper的抽象类,然后每一个运算符都覆盖该oper。

PayDay.java
BetterPayDay.java
相比如使用switch区分不同的枚举,可以使用嵌套枚举类作为策略枚举,对外层枚举进行区分。
这个在javac编译器中有使用。参考 javac编译器框架1——词法和语法分析器 中对Token类型的定义

3.2 将局部变量的作用域最小化

1、 在第一次使用的地方进行声明
2、 局部变量都是要自行初始化,初始化条件不满足,就不要声明
最小化的好处,减小局部变量表的大小,提示性能;同时避免局部变量过早声明导致不正确的使用。

3.3 精确计算避免使用float和double

可以使用int或者long以及BigDecimal。

3.4 当心字符串连接的性能

在存在大量字符串拼接或者大型字符串拼接的时候,尽量使用StringBuilder和StringBuffer。
参考StringUnion.java
+拼接字符串的性能很低,所以如果能省掉拼接过程,会大幅提高性能。也间接证明+性能很低。
程序运行结果:

直接打印模式,次数:100000000:spend time :7668ms
先判断再打印模式,次数:100000000:spend time :4ms

3.5 控制方法的大小

参考

  • 1)享学课堂Mark老师笔记
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351