乐趣区

关于java:优秀程序员都在注意的十个点

1. 多走半里路

很多事件并不难,只是不足多走半里路的习惯!

反例

public boolean isInValid(String str) {if (str == null || str.trim().length() == 0) {return true;}
    return false;
}

多走一步,海阔天空

public boolean isInValid(String str) {return (str == null) || (str.trim().length() == 0);
}

是个程序员都晓得哪个更好!

还有一种见过很屡次的代码:

public boolean isEmptyName() {return StringUtils.isEmpty(name)? true: false;
}

难道不感觉到多余吗?

再走半步,山清水秀

public boolean isEmptyName() {return StringUtils.isEmpty(name);
}

2. 空对象

NullPointException,让咱们防不胜防;尤其是应用第三方 API,如果抛出这个异样,会让人有骂街的激动。所以:若不想踩坑,请先别给他人挖坑。

现实要求:咱们生产的所有 public 带返回值的办法体中,不应该呈现“return null”字样。空对象就是这一思维的落地实现。

案例:查问并返回一个名字为 steven 的老师或者学生。

public static SearchFilter name(String name) {return human -> human.getName().equalsIgnoreCase(name);
}

public Human find(SearchFilter filter) {for (Human human : humans) {if (filter.isMatched(human)) {return human;}
    }
    return new NullHuman();   // 如果你返回 NULL,总有一天你会挨骂!}

//Test
assertFalse(edu.find(name("steven")).isNull());

3. 单实例情结

谈起设计模式,很多人会感觉高大上,于是当学会了其中一个时,便会不加节制的应用。

单例,GOF 中最简略的一个设计模式,很好用、也十分不便,但说实话很多人在滥用。咱们的零碎中随处可见,但用前请叩问本人该类真的是在零碎当中有并且只能有一个实例吗?

否则请回绝单实例。太多的单实例会给你的自动化测试带来无穷的懊恼。

4. 充沛应用枚举

枚举有一些比拟弱小的个性容易被忽视,比方枚举对象自身也能够携带变量;这一个性让枚举在更多的场合施展不可代替的功能。

举例:不同武器具备不同的杀伤力,杀伤力变量能够携带到武器的枚举值中。

public enum EquipmentEnum {Staff(20), Hammer(10);
    double playerRisedAbility;

    EquipmentEnum(double playerRiseAbility) {this.playerRisedAbility = playerRiseAbility;}

    public double getRaiseAbility(double originalAbility) {return Double.sum(originalAbility, playerRisedAbility);
    }
}

5. 进步正文品质

30% 的代码正文比的时代曾经成为过来, 最好的正文的就是无需正文 ,程序员应该致力于通过命名让正文隐没。

大量的实践证明,随着重构频率越来越高,重构过程中随着代码的变更同步更新正文的可能性简直为零。长此以往,正文与代码就是背道而驰。

6. 面向客户的命名

好的命名可能愉悦读者的情绪,让人有想一睹作者真面目的激动!

案例:

一个房地产开发商一个新的楼盘收盘,原价 80 万每套,有如下优惠策略,但优惠政策可能随着楼盘存量状况会不一样,为开发商写一个房款计算程序

  1. 老客户买二套房可优惠 4%,可累加
  2. 一次性全款客户可优惠 3%,可累加

public class Customer {Benefiter benefit = new NullBenefiter();

    public void is(Benefiter benefits) { // 本来的 set 办法,重命名会带来意想不到的成果。this.benefit = benefits;
    }

    public double shouldPay(double srcPrice) {return srcPrice - benefit.benefit(srcPrice);
    }
}

@FunctionalInterface
public interface Benefiter {abstract double benefit(double srcPrice);

    default Benefiter and(final Benefiter otherPolicy) {return srcPrice -> (benefit(srcPrice) + otherPolicy.benefit(srcPrice));
    }
}

受害于良好命名,客户代码语义跃然纸上:customer.is(oldCustomer().and(fullPay()));

7. 应用多维数组

数组是任何一门绝对高级的机器语言的必备数据结构,然而对面向对象开发人员而言,仿佛对它有所疏忽。

在一些特定的场景下,它能起到意想不到的成果。

案例:美元、法郎、人民币三币种间换算。其中美元:法郎 =1:2;美元:人民币 =1:8;

public class ExchangeRate {
    public static final int DOLLAR = 0;
    public static final int FRANC = 1;
    public static final int YMB = 2;
    private static final double[][] rates = {   // 二维数组定义币种之间的汇率,简略高效
            {1.0d, 2.0d, 8.0d},
            {0.5d, 1.0d, 4.0d},
            {0.125d, 0.25d, 1.0d}
    };

    public static double getRateOf(Currency src, Currency tgt) {return rates[src.ID][tgt.ID];
    }
}

public class Cash {
    private double value;
    private Currency unit;

    public Cash(double value, Currency unit) {
        this.value = value;
        this.unit = unit;
    }

    @Override
    public boolean equals(Object obj) {if (obj instanceof Cash) {Cash other = (Cash) obj;
            return value == other.value * getRateOf(other.unit, unit);
        }
        return false;
    }
}

如果汇率的二维数组应用配置文件定义并初始化,那还能够将设计晋升一个新的高度——易于扩大,甚至不需批改任何 Java 代码即可实现币种的扩大。

8. 规约函数入参

当咱们调用内部 API 时,最现实的就是零入参,即使有入参也心愿是类型明确且范畴可枚举的,这样会让咱们应用这个 API 时更具安全感!心同此理,当你把一个函数申明为 public 时,请审慎地定义它的入参。

如果把上述案例中获取两种币种之间的汇率函数:

public static double getRateOf(Currency src, Currency tgt) {return rates[src.ID][tgt.ID];
}

定义为

public static double getRateOf(int src, int tgt) {return rates[src][tgt];
}

尽管函数实现简略了一些,但可想而知,这个 API 会让使用者很忌惮!数组越界异样必定是常常产生。

相同通过枚举规约了入参的类型和范畴,给用户一些固定选项,使用者少了很多顾虑,而咱们的程序也更加平安。

所以:咱们对外提供的 API 入参类型尽量少用 String、Int 这种根本类型,给使用者施展的空间越大,犯错的可能越大,因为你把危险裸露在不受控的用户手里。

9. 常常进行封装去重

你是否为重复地编写相似“if (tasks != null && tasks.size() > 0)”或者“if (name != null && (!name.isEmpty()))”的代码而心浮气躁,其实你齐全能够拯救本人。

封装一下

public class CollectionUtil {public static boolean isEmpty(Collection collection) {return collection == null || collection.isEmpty();
    }
}

以及

public class StringUtil {public static boolean isEmpty(String context) {return context == null || context.isEmpty();
    }
}

所有变得非常简单,情绪好了,效率也就高了!

10. 化解 if/else 的毒素

咱们的零碎充斥着 if/else 的逻辑,因为它逻辑“简略”、易用!但随着时间推移、需要的扩大,有一天你会发现自己都看不懂本人写的 if/else。

所以一开始就要学会回绝这种逻辑的嵌套,又或者是当你看嵌套的简单逻辑,大胆的对它进行重构。

案例:输出一个 1 -1000 的数值 N,如果 N 是 3 或者 3 的倍数时, 返回“FIZZ”;如果 N 是 5 或者 5 的倍数时, 返回“BUZZ”;既是 3 的倍数又是 5 的倍数时, 返回“FIZZBUZZ”;其余的则输入 N。

原实现:披着对象外壳的面向过程代码

public String say(int input) throws Exception {if ( input < 1 || input > 1000){throw new Exception("Invalid input");
    }
    if (input % 15 == 0) {return "FIZZBUZZ";}
    if (input % 5 == 0) {return "BUZZ";}
    if (input % 3 == 0) {return "FIZZ";}
    return String.valueOf(input);
}

嗅一嗅其中的坏滋味,如果未来需要扩大,比方引进 7 的倍数。照此逻辑,持续增加 if,问题是解决了,但总有一天你会狐疑人生!

改良一:引入责任链和模板办法模式

public String say(int input) throws Exception {if (input < 1 || input > 1000) {throw new Exception("Invalid input");
    }
    DefaultParser defaultParser = new DefaultParser(null);
    MultiOfThreeParser multiOfThreeParser = new MultiOfThreeParser(defaultParser);
    MultiOfFiveParser multiFiveParser = new MultiOfFiveParser(multiOfThreeParser);
    MultiOfFifteenParser fifteenPaser = new MultiOfFifteenParser(multiFiveParser);
    return fifteenPaser.parse(input);
}

public abstract class Parser {abstract boolean isFixedResponsibility(int inputContext);
    abstract String response(int inputContext) throws Exception;
    public String parse(int inputContext) throws Exception  {if (isFixedResponsibility(inputContext))     {return response(inputContext);
        }
        if (nextParser != null) {return nextParser.parse(inputContext);
        }
        return NULL;
    }
}

public class MultiOfFifteenParser extends Parser {public MultiOfFifteenParser(Parser nextParser) {super(nextParser);
    }
    
    @Override
    public String response(int inputContext) throws Exception {return FLAG_FOR_MULIT_OF_FIFTEEN;}
    
    @Override
    boolean isFixedResponsibility(int inputContext)    {return inputContext % 15 == 0;}    
}

看起来好多了,但感觉如同还有哪儿不太对劲!

改良二:彻底穿上对象的外袍

敏锐的读者可能还会发现上述改良还存在轻微的小问题,那就是 say 办法外面的异样分支解决。怎么还存在一个 if,对于一个完美主义强迫症患者而言,它的存在就是一个劫难。持续改良一下:

public String say(int input) throws Exception {DefaultParser defaultParser = new DefaultParser(null);
    MultiOfThreeParser multiOfThreeParser = new MultiOfThreeParser(defaultParser);
    MultiOfFiveParser multiOfFiveParser = new MultiOfFiveParser(multiOfThreeParser);
    MultiOfFifteenParser FifteenPaser = new MultiOfFifteenParser(multiOfFiveParser);
    InvalidNumberParser invalidNumberPaser = new InvalidNumberParser(FifteenPaser);
    return invalidNumberPaser.parse(input);
}

public class InvalidNumberParser extends Parser {public InvalidNumberParser(Parser nextParser) {super(nextParser);
    }
    
    @Override
    String response(int inputContext) throws Exception {throw new Exception("Invalid input");
    }
    
    @Override
    boolean isFixedResponsibility(int inputContext){return (inputContext < L_THRESHOLD) || (inputContext > H_THRESHOLD);
    }
}

OK,Perfect!

退出移动版