黑客(程序員)也是創做者,與畫家、建築師、做家同樣。 ——《黑客與畫家》java
在咱們日常開發過程當中,因爲項目時間緊張,代碼能夠用就好,每每會忽視代碼的質量問題。甚至有些複製粘貼過來,不加以整理規範。每每致使項目後期難以維護,更別說後續接手項目的人。因此啊,咱們要編寫出優雅的代碼,方便你我他,豈不美哉?程序員
下面分享一些我在開發中經常使用的編碼中小建議
,若有不妥,歡迎你們一塊兒交流學習。ide
衛語句,就是把複雜的條件表達式拆分紅多個條件表達式。好比 多個 if-elseif-else
嵌套, 能夠拆分紅多個 if
。以下面代碼函數
-------------------- before --------------------
public void today() {
if (isWeekend()) {
if (isFee()) {
System.out.println("study Android");
} else {
System.out.println("play a game");
}
} else {
System.out.println("go to work");
}
}
-------------------- after (建議) --------------------
public void today() {
// 提早過濾掉`特殊狀況`
if (!isWeekend()) {
System.out.println("go to work");
return; // 提早return
}
//提早過濾掉`特殊狀況`
if (isFee()) {
System.out.println("study Android");
return; // 提早return
}
// 更關注於 `核心業務`代碼實現。
System.out.println("play a game");
}
複製代碼
提早過濾掉
特殊
狀況,更關注核心
業務邏輯學習
咱們日常開發的時候,應該編寫小而美
函數,避免函數過長
。通常函數最好在15行之內(建議
) 咱們看看下面代碼:優化
-------------------- before --------------------
if (age > 0 && age < 18){
System.out.println("小孩子");
}
if (number.length() == 11){
System.out.println("符合手機號");
}
-------------------- after (建議) --------------------
private static boolean isChild(int age) {
return age > 0 && age < 18;
}
private static boolean isPhoneNumber(String number) {
return number.length() == 11;
}
if (isChild(age)){
System.out.println("小孩子");
}
if (isPhoneNumber(number)){
System.out.println("符合手機號");
}
複製代碼
把判斷語句抽取成一個個
小函數
, 這樣代碼更加清晰明瞭。this
迪米特法則(Law of Demeter)又叫做最少知識原則(Least Knowledge Principle 簡寫LKP),就是說一個對象應當對其餘對象有盡可能少
的瞭解
。例如 當一條語句中 一個對象出現兩個 .
(student.getName().equals("張三")
) 就是代碼壞味道的表現,以下代碼所示。編碼
-------------------- before --------------------
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) {
Student student = new Student("張三");
// 注意看這裏,
// 這裏獲取 student的name屬性,在根據name屬性進行判斷
if (student.getName().equals("張三")) {
System.out.println("個人好朋友是 " + student.getName());
}
}
-------------------- after (建議) --------------------
public class Student {
... 省略name代碼
// 新增一個 判斷是不是個人好朋友方法
public boolean isGoodFriend(){
return this.name.equals("張三");
}
}
public static void main(String[] args) {
Student student = new Student("張三");
// 根據迪米特法則,把判斷邏輯,抽取到 Student 內部,暴露出方法(isGoodFriend)
if (student.isGoodFriend()){
System.out.println("個人好朋友是 " + student.getName());
}
}
複製代碼
IDEA/Android Studio 抽取方法快捷鍵:
option + command + M
spa
咱們在日常開發中,會使用到map
,可是在面向對象開發理念中,一個 map
的使用,每每就會錯過了 Java Bean
。建議使用 Java Bean
更直觀。以下代碼:設計
public static void main(String[] args) {
-------------------- before --------------------
Map<String, String> studentMap = new HashMap<>();
studentMap.put("張三", "男");
studentMap.put("小紅", "女");
studentMap.put("李四", "男");
studentMap.forEach((name, sex) -> {
System.out.println(name + " : " + sex);
});
-------------------- after (建議) --------------------
List<Student> students = new ArrayList<>();
students.add(new Student("張三", "男"));
students.add(new Student("小紅", "女"));
students.add(new Student("李四", "男"));
for (Student student : students) {
System.out.println(student.getName() + ":" + student.getSex());
}
}
複製代碼
筆者在編寫這點時候,有所顧慮。確定有小夥伴跳出來講,map
和 bean
不是同樣嗎?用map
我還能夠省去思考如何命名Class
呢。可是從代碼規範來講,這樣代碼設計不是更符合 Java 面向對象
的思想嗎?
Java 8 API添加了一個新的抽象稱爲流Stream
,可讓你以一種聲明的方式處理數據。使得代碼調用起來更加優雅~ 直接來看代碼:
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student("張三", "男"));
students.add(new Student("李四", "男"));
students.add(new Student("小紅", "女"));
students.add(new Student("小花", "女"));
students.add(new Student("小紅", "女"));
-------------------- before --------------------
//統計男生個數
//傳統的 for each 循環遍歷
long boyCount = 0;
for (Student student : students) {
if (student.isBoy()) {
boyCount++;
}
}
System.out.println("男生個數 = " + boyCount);
-------------------- after (建議) --------------------
//統計男生個數
//stream 流遍歷
long count = students.stream()
.filter(Student::isBoy) // 等同於.filter(student -> student.isBoy())
.count();
System.out.println("男生個數 = " + boyCount);
}
複製代碼
相比與 傳統的 For
循環,更推薦你們使用 stream
遍歷。 stream
流的鏈式調用,還有許多騷操做,如 sorted
, map
, collect
等操做符,能夠省去沒必要要if-else
,count
等判斷邏輯。
Java 三大特性之一,多態
,相信你們都不會陌生,多態的好處就是根據對象不一樣類型採起不一樣的的行爲。咱們經常在編寫 switch
語句的時候,若是改用多態,能夠把每一個分支,抽取到一個子類內的覆寫函數中,這就更加靈活。
咱們有這樣一個需求,編寫一個簡單計算器方法,咱們先來看一小段代碼:
-------------------- before --------------------
public static int getResult(int numberA, int numberB, String operate) {
int result = 0;
switch (operate) {
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
result = numberA / numberB;
break;
}
return result;
}
-------------------- after (建議) --------------------
abstract class Operate {
abstract int compute(int numberA, int numberB);
}
class AddOperate extends Operate {
@Override
int compute(int numberA, int numberB) {
// TODO 在這裏處理相關邏輯
return numberA + numberB;
}
}
... SubOperate, MulOperate, DivOperate 也和 AddOperate同樣這裏就不一一貼出
public static int getResult(int numberA, int numberB, String operate) {
int result = 0;
switch (operate) {
case "+":
result = new AddOperate().compute(numberA, numberB);
break;
case "-":
result = new SubOperate().compute(numberA, numberB);
break;
case "*":
result = new MulOperate().compute(numberA, numberB);
break;
case "/":
result = new DivOperate().compute(numberA, numberB);
break;
}
return result;
}
複製代碼
有小夥伴可能會說,你這不是更復雜了嗎?
對比起單純的switch
,咱們能夠這樣理解:
加法
的邏輯, 咱們只須要修改對應 AddOperate
類就能夠了。避免直接修改getResult
方法可是這裏會存在一些問題,若是咱們新增一個平方根
,平方
等計算方式, 就須要修改 switch
裏面的邏輯,新增一個條件分支。下面咱們再來看看更進一步的優化。
經過上面例子,咱們能夠進一步優化,經過反射
生成對應的 Class
,而後在調用compute
方法。以下代碼:
public static <T extends Operate> int getResult(int numberA, int numberB, Class<T> clz) {
int result = 0;
try {
return clz.newInstance().compute(numberA, numberB);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return result;
}
}
public static void main(String[] args) {
// 調用的時候直接傳遞 class 便可
System.out.println(getResult(1, 2, SumOpearte.class));
}
複製代碼
根據傳入 class
參數,而後生成對應 Opearte
處理類, 對比多態方式,咱們這裏採用反射,使得代碼耦合度大大下降,若是在增長平方根
,平方
等計算方式。咱們只須要 新增一個 class
繼承 Opearte
便可,getResult
不用作任何修改。
須要注意的是,不是全部
switch
語句都須要這樣替換, 在面對簡單的switch
語句,就沒必要要了, 避免過分設計
的嫌疑。以下代碼:
public String getResult(int typeCode) {
String type = "";
switch (typeCode) {
case 0:
type = "加法";
break;
case 1:
type = "減法";
break;
case 2:
type = "乘法";
break;
case 3:
type = "觸發";
break;
}
return type;
}
複製代碼
以上就是我在編碼上的一些小建議
,若有不妥,歡迎你們一塊兒交流學習。