关于java:解锁新姿势-兄dei你代码需要优化了

50次阅读

共计 5810 个字符,预计需要花费 15 分钟才能阅读完成。

前言

在咱们平时开发过程中,因为我的项目工夫缓和,代码能够用就好,往往会漠视代码的品质问题。甚至有些复制粘贴过去,不加以整顿标准。往往导致我的项目前期难以保护,更别说后续接手我的项目的人。所以啊,咱们要编写出优雅的代码,不便你我他,岂不美哉?

上面分享一些我在开发中罕用的编码中 小倡议,如有不妥,欢送大家一起交流学习。

卫语句

卫语句,就是把简单的条件表达式拆分成多个条件表达式。比方 多个 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("合乎手机号");
}

把判断语句抽取成一个个 小函数, 这样代码更加清晰明了。

迪米特法令

概念:

迪米特法令(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 (StringUtils.isNotBlank(student.getName()) && student.getName().equals("张三")) {System.out.println("我的好敌人是" + student.getName());
    }
}


 -------------------- after (倡议) --------------------
 
 public class Student {

    ... 省略 name 代码

    // 新增一个 判断是否是我的好敌人办法
    public boolean isGoodFriend(){return StringUtils.isNotBlank(this.name) && 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

Map 提取对象

咱们在平时开发中,会应用到 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());
        }
    }

笔者在编写这点时候,有所顾虑。必定有小伙伴跳出来说,mapbean 不是一样吗?用 map 我还能够省去思考如何命名Class 呢。然而从代码标准来说,这样代码设计不是更合乎 Java 面向对象 的思维吗?

Stream

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-elsecount 等判断逻辑。

多态

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;
}

最初

以上就是我在编码上的一些 小倡议,如有不妥,欢送大家退出我的十年 Java 学习园地一起交流学习。

正文完
 0