15阶段回顾与复习

140 阅读3分钟
  • 人类不能理解flag代码

    • 8-how-many-prime-numbers
package com.github.hcsp.controlflow;

public class Main {
    public static void main(String[] args) {
        System.out.println(howManyPrimeNumbers(5));
    }

    /**
     * 给定一个数字n,返回1到n之间的质数(素数)个数,不包括n本身。
     *
     * <p>例如,n=5,返回2,因为15之间有2个质数:23。
     *
     * <p>提示:对于正整数n,如果用2到Math.sqrt(n)+1之间的所有整数去除,均无法整除,则n为质数。
     *
     * @param n 给定的数字
     * @return 1到n之间(不包括n)质数的个数
     */
    public static int howManyPrimeNumbers(int n) {
        int k = 0;
        for (int i = 2; i < n; i++) {
            boolean flag = true;
            for (int j = 2; j < Math.sqrt(n) + 1; j++) {
                if ((i % j == 0) && (i != j)) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                k += 1;
            }
        }
        return k;
    }
}
  • 用人类更能理解的方式
  • 写出让机器能阅读的代码一点都不难,难的是写出让人能阅读理解的代码
package com.github.hcsp.controlflow;

public class Main {
    public static void main(String[] args) {
        System.out.println(howManyPrimeNumbers(5));
    }

    /**
     * 给定一个数字n,返回1到n之间的质数(素数)个数,不包括n本身。
     *
     * <p>例如,n=5,返回2,因为1到5之间有2个质数:2和3。
     *
     * <p>提示:对于正整数n,如果用2到Math.sqrt(n)+1之间的所有整数去除,均无法整除,则n为质数。
     *
     * @param n 给定的数字
     * @return 1到n之间(不包括n)质数的个数
     */
    public static int howManyPrimeNumbers(int n) {
        int k = 0;
        for (int i = 2; i < n; i++) {
            if (isPrimeNumber(i)) {
                k += 1;
            }
        }
        return k;
    }

    private static boolean isPrimeNumber(int i) {
        for (int j = 2; j < Math.sqrt(i) + 1; j++) {
            if ((i % j == 0) && (i != j)) {
                return false;
            }
        }
        return true;
    }
}

什么是好的代码

  • 短小精悍,且容易被人类阅读和理解

java中字符串是不可变的对象

  • 如果执行+=操作就是创建了新的对象
    1.png
  • 用StringBuilder比较好

1.png

package com.github.hcsp.controlflow;

public class Main {
    /**
     * 打印从start到end区间所有的奇数,包括start和end本身(若符合条件)。 注意,数字之间用英文逗号分隔。
     *
     * <p>例如,start=1,end=5,则打印1,3,5 又如,start=-2,end=2,则打印-1,1
     *
     * @param start 区间开始
     * @param end   区间结束
     */
    public static void printOddNumbersBetween(int start, int end) {
//        String s = "";
//        for (int i = start; i <= end; i++) {
//            if (i % 2 != 0) {
//                s += i + ",";
//            }
//            System.out.println(s);
//        }

        StringBuilder s = new StringBuilder();

        for (int i = start; i <= end; i++) {
            if (i % 2 != 0) {
                s.append(i).append(",");
            }
            System.out.println(s);
        }
    }

    public static void main(String[] args) {
        printOddNumbersBetween(1, 5);
        printOddNumbersBetween(-2, 2);
    }
}

不要用magic number,至少要写成常量

double IEEE 754 浮点数表 示

  • Inf-> Infinity无限大, Nan-> Not a Number,不是实数
  • 正浮点数除以0为+的nan,负浮点数除以0为-的nan

try-catch

  • 成本非常高,try-catch的异常是有调用栈的
    其次没法保证try...catch的异常是能希望被捕获的异常
  • 除非没有办法,尽量不要用try...catch补获异常

代码可读性

  • 避免多层嵌套
  • 避免提交注释上去,如果之前能写出的代码之后肯定也能写出

git fetch的使用,添加远程仓库

3.png

3.png

pull request

  • close中搜索模范 代码

重构的技巧

  • refactor然后点击extract抽取成一个方法
  • 好处,复用代码,有意义的名字有名字jvm会优化不用担心栈

reatainAll,hashmap和ArrayList的性能区别

  • hashset是O(1)的
  • ArrayList是O(n2)

代码写的越少越不容易出bug

循环创建新的对象

  • 之前的对象会被垃圾回收

生成equals同时生成hash code的原因

  • 这是一个最佳事件

碰到异常

  • 最后抛出异常,不要只打印
  • 如果一定要写ignored,就要仔细填写ignore的原因
catch (Exception ignored) {
    // ignored
}
throw new RuntimeException(e);

正则表达式

  • 这个操作要放到全局,这样不会多次编译

java bean转json

  • 只和getter有关系

警告错误的配置

  • Inspections错误的配置

碰到重复代码

  • 抽成方法

异或会有坑

  • i和j相同会有问题
  • 工程师的指责是保证程序正确稳定的运行,而不是为了炫技

尽量不要用flag

  • 人阅读理解起来会很困难
  • 绝大多数大学老师都不是合格的工程师
  • 把if...else放到一个小的空间

不要把全局变量当作锁

多层人类理解起来很难

  • 分层

optimize import

  • 去掉无用导入

4.png

  • 也可以对真哥哥文件夹使用快捷键,进行优化导入

Java命名约定

  • 类大写
  • 局部变量驼峰
  • 常量大写字母+下划线
  • 包纯小写

右键-inspect

  • 找到代码的问题
  • 然后一个个去解决

尽量导入不要用*

java doc

  • java的世界中有三种注释

    • 单行
    • 两个斜杠多行
    • java doc非常特殊,是会被编译的。斜杠2个*号开始,会被渲染成html
@code 会被渲染成行内的html,好看的html
// @开头的是特殊的标签

编译是怎么做的

  • 文本文件 .java,首先会经历Lexer和Tokenizer变成一个个的词法单元,比如 int 空格 a = 123 ;,这个叫词法分析
  • 然后会组织成词法树,语法分析用来检查parsing符不符合语法,lexing只是用来检测符不符合一个单元
  • 有了树之后就可以做更多的检查,总之就是沿着树挨个去检查 5.png

避免空指针

// 不好
methodName.equals("getClass)
// 应该写成
"getClass".equals(methodName)