├── src
└── main
│ └── java
│ ├── chapter_11
│ ├── README.md
│ ├── Example3.js
│ ├── Example5.js
│ ├── Example1.js
│ ├── Example2.java
│ ├── Example6.java
│ └── Example4.java
│ ├── chapter_12
│ ├── README.md
│ ├── Example1.js
│ ├── Example2.java
│ └── Example3.java
│ ├── chapter_14
│ ├── README.md
│ ├── Example1.java
│ ├── Example3.java
│ ├── Example4.java
│ ├── Example2.java
│ └── access.log.txt
│ ├── chapter_15
│ └── README.md
│ ├── chapter_16
│ └── README.md
│ ├── chapter_13
│ ├── README.md
│ ├── Example2.js
│ ├── Example1.java
│ └── Example3.java
│ ├── chapter_02
│ ├── README.md
│ ├── Node.java
│ ├── Example4.java
│ ├── Coder.java
│ ├── Example2.java
│ ├── Example1.java
│ └── Example3.java
│ ├── chapter_10
│ ├── README.md
│ ├── Example6.java
│ ├── Example3.java
│ ├── Example2.java
│ ├── Example4.js
│ ├── Example1.java
│ ├── Example7.html
│ └── Example5.java
│ ├── chapter_05
│ ├── README.md
│ ├── Example6.java
│ ├── Example4.java
│ ├── Example1.java
│ ├── Example3.java
│ ├── Example2.java
│ └── Example5.java
│ ├── chapter_09
│ ├── README.md
│ ├── Example1.java
│ ├── Example4.java
│ ├── Example3.java
│ ├── Example2.java
│ ├── Example6.java
│ └── Example5.js
│ ├── chapter_07
│ ├── README.md
│ ├── Example10.java
│ ├── Example9.java
│ ├── Example12.java
│ ├── Example11.java
│ └── Example8.java
│ ├── chapter_04
│ ├── README.md
│ ├── Example1.java
│ ├── Example4.java
│ ├── Example2.java
│ ├── Example3.java
│ └── Example5.java
│ ├── chapter_06
│ ├── Example4.java
│ ├── Example6.java
│ ├── Example3.java
│ ├── README.md
│ ├── Example5.java
│ ├── Example1.java
│ ├── Example2.java
│ └── Example7.java
│ ├── chapter_03
│ ├── BinaryTree.java
│ ├── Example5.java
│ ├── Example1.java
│ ├── Example4.java
│ ├── Example6.java
│ ├── README.md
│ ├── Example2.java
│ └── Example3.java
│ └── chapter_08
│ ├── README.md
│ ├── Example3.java
│ ├── Example1.java
│ ├── Example4.java
│ ├── Example6.java
│ ├── Example2.java
│ └── Example5.java
├── README.md
├── pom.xml
├── LICENSE
└── .gitignore
/src/main/java/chapter_11/README.md:
--------------------------------------------------------------------------------
1 | # 抽取无关的代码
--------------------------------------------------------------------------------
/src/main/java/chapter_12/README.md:
--------------------------------------------------------------------------------
1 | # 一次只干一件事
--------------------------------------------------------------------------------
/src/main/java/chapter_14/README.md:
--------------------------------------------------------------------------------
1 | # 少写点代码
--------------------------------------------------------------------------------
/src/main/java/chapter_15/README.md:
--------------------------------------------------------------------------------
1 | # 测试和可读性
--------------------------------------------------------------------------------
/src/main/java/chapter_16/README.md:
--------------------------------------------------------------------------------
1 | # 你的最终考验
--------------------------------------------------------------------------------
/src/main/java/chapter_13/README.md:
--------------------------------------------------------------------------------
1 | # 把想法变成代码
2 |
--------------------------------------------------------------------------------
/src/main/java/chapter_02/README.md:
--------------------------------------------------------------------------------
1 | # 写让人理解的代码
2 |
3 | 代码的写法应该使理解代码的人所需要的时间最小化。
--------------------------------------------------------------------------------
/src/main/java/chapter_10/README.md:
--------------------------------------------------------------------------------
1 | # 变量和可读性
2 |
3 | 1. 减少变量,通过立刻处理结果来消除中间变量。
4 | 2. 减少变量作用域,作用域越小越好。
5 | 3. 变量只写一次最好,只设置一次的变量会让代码变得更容易理解。
--------------------------------------------------------------------------------
/src/main/java/chapter_05/README.md:
--------------------------------------------------------------------------------
1 | # 写代码也需要审美?
2 |
3 | 1. 如果多个代码块做同样的事,尝试让它们有同样的剪影
4 | 2. 把代码块按照 “列” 对齐可以让代码更容易阅读
5 | 3. 如果一段代码中用到了 A、B、C,那么在使用它们的下方就应该保持顺序一致
6 | 4. 使用空行将大段的代码分为逻辑上的“段落”
7 |
--------------------------------------------------------------------------------
/src/main/java/chapter_09/README.md:
--------------------------------------------------------------------------------
1 | # 拆分又臭又长的表达式
2 |
3 | 引入“解释变量”代替较长的子表达式,有三个好处:
4 |
5 | 1. 它把巨大的表达式拆分成一个小段
6 | 2. 通过简单的名字来描述一个子表达式,让代码文档化
7 | 3. 它帮助读者识别代码中重要的概念
8 |
9 | **用德摩根定理来操作逻辑表达式**
--------------------------------------------------------------------------------
/src/main/java/chapter_07/README.md:
--------------------------------------------------------------------------------
1 | # 什么样的注释是好的
2 |
3 | ## 写出言简意赅的注释
4 |
5 | - 当像 “这里” 和 “it” 这样的代词可能指代多个事物时,避免使用它们
6 | - 尽量精确的描述方法行为
7 | - 在注释中用精心挑选的输入/输出例子进行说明
8 | - 声明代码的高层次意图,而非明显的细节
9 | - 用含义丰富的词来使注释更加简洁
--------------------------------------------------------------------------------
/src/main/java/chapter_10/Example6.java:
--------------------------------------------------------------------------------
1 | package chapter_10;
2 |
3 | /**
4 | * 只写一次的变量更好
5 | *
6 | * @author biezhi
7 | * @date 2018/7/25
8 | */
9 | public class Example6 {
10 |
11 | public static final int NUM_THREADS = 10;
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/chapter_04/README.md:
--------------------------------------------------------------------------------
1 | # 让人不会误解的名字
2 |
3 | 不会误解的名字是最好的名字——阅读代码的人应该理解你的本意,并且不会有其他的理解。
4 |
5 | - 表示上限和下限:max min
6 | - 表示包含的范围:first last
7 | - 表示包含、排除某个范围:begin end
8 |
9 | 命名一个 bool 类型的值,应该使用 is 、 has 这样的词来明确它所表达的含义。
10 | 避免使用反义的词,比如 disable。
11 |
12 | 要小心用户对特定词的期望。例如用户会认为 get 或 size 是一个轻量的方法。
--------------------------------------------------------------------------------
/src/main/java/chapter_05/Example6.java:
--------------------------------------------------------------------------------
1 | package chapter_05;
2 |
3 | /**
4 | * 个人风格与一致性
5 | *
6 | * @author biezhi
7 | * @date 2018/7/3
8 | */
9 | public class Example6 {
10 |
11 | class Tigger {
12 |
13 | }
14 |
15 | // or
16 |
17 | class Coder
18 | {
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/chapter_02/Node.java:
--------------------------------------------------------------------------------
1 | package chapter_02;
2 |
3 | /**
4 | * @author biezhi
5 | * @date 2018/6/24
6 | */
7 | public class Node {
8 |
9 | private Node next;
10 |
11 | public Node next() {
12 | return this.next;
13 | }
14 |
15 | public String data(){
16 | return "";
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/chapter_04/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_04;
2 |
3 | /**
4 | * 截取字符串
5 | *
6 | * @author biezhi
7 | * @date 2018/6/27
8 | */
9 | public class Example1 {
10 |
11 | private void truncate(String text, int maxChars) {
12 |
13 | }
14 |
15 | public void invoke() {
16 | this.truncate("hello world", 5);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/chapter_02/Example4.java:
--------------------------------------------------------------------------------
1 | package chapter_02;
2 |
3 | /**
4 | * @author biezhi
5 | * @date 2018/6/24
6 | */
7 | public class Example4 {
8 |
9 | private int hash;
10 | private int c = 2018;
11 |
12 | public void calcHash() {
13 | // Fast version of "hash = (65599 * hash) + c"
14 | hash = (hash << 6) + (hash << 16) - hash + c;
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/chapter_14/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_14;
2 |
3 | /**
4 | * 商店定位器
5 | *
6 | * @author biezhi
7 | * @date 2018/9/24
8 | */
9 | public class Example1 {
10 |
11 | /**
12 | * 给某个用户实现一个“商店定位器”
13 | *
14 | * 对于任何给定用户的经纬度,找到距离该经纬度最近的商店。
15 | *
16 | * 1. 当位置处理国际日期分界线两侧的情况
17 | * 2. 接近北极或南极的位置
18 | * 3. 按 “每英里所跨经纬度” 不同,处理地球表面的曲度
19 | */
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/chapter_04/Example4.java:
--------------------------------------------------------------------------------
1 | package chapter_04;
2 |
3 | /**
4 | * @author biezhi
5 | * @date 2018/6/27
6 | */
7 | public class Example4 {
8 |
9 | boolean hasPassword = true;
10 |
11 | boolean useSSL = false;
12 |
13 |
14 | public int computeChinaFriends(String username) {
15 | // 访问数据库查询 username 的所有访客朋友,筛选计算出所有在中国的访问朋友,并计算个数返回
16 | return -1;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/chapter_07/Example10.java:
--------------------------------------------------------------------------------
1 | package chapter_07;
2 |
3 | /**
4 | * 用输入/输出例子来说明特殊情况
5 | *
6 | * @author biezhi
7 | * @date 2018/7/7
8 | */
9 | public class Example10 {
10 |
11 | /**
12 | * 从 src 中移除以 chars 开头/结尾的字符
13 | *
14 | * Example: strip("abba/a/ba", "ab") return "/a/"
15 | */
16 | public String strip(String src, String chars) {
17 | // logic
18 | return "";
19 | }
20 |
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/chapter_02/Coder.java:
--------------------------------------------------------------------------------
1 | package chapter_02;
2 |
3 | /**
4 | * 皮卡丘
5 | *
6 | * @author biezhi
7 | * @date 2018/6/24
8 | */
9 | public class Coder {
10 |
11 | private boolean hasGirlFriend;
12 |
13 | public Coder(boolean hasGirlFriend) {
14 | this.hasGirlFriend = hasGirlFriend;
15 | }
16 |
17 | public boolean hasGirlFriend() {
18 | return this.hasGirlFriend;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/chapter_06/Example4.java:
--------------------------------------------------------------------------------
1 | package chapter_06;
2 |
3 | /**
4 | * 为代码中的瑕疵写注释
5 | *
6 | * @author biezhi
7 | * @date 2018/7/6
8 | */
9 | public class Example4 {
10 |
11 | /**
12 | * TODO 优化算法的性能
13 | */
14 | public void foo() {
15 |
16 | }
17 |
18 | public void bar(String suffix) {
19 | if ("jpg".equals(suffix)) {
20 | System.out.println(suffix);
21 | } else {
22 | // TODO 处理 jpg 之外的其他格式
23 | }
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/chapter_11/Example3.js:
--------------------------------------------------------------------------------
1 | $.post({
2 | url: 'http://example.com/submit',
3 | data: data,
4 | success: function (response_data) {
5 | alert(format_pretty(response_data));
6 | // 继续处理响应数据
7 | }
8 | });
9 |
10 | function format_pretty(json_object) {
11 | var str = '{\n';
12 | for (var key in json_object) {
13 | str += " " + key + " = " + response_data[key] + "\n";
14 | }
15 | return str + "}";
16 | }
--------------------------------------------------------------------------------
/src/main/java/chapter_03/BinaryTree.java:
--------------------------------------------------------------------------------
1 | package chapter_03;
2 |
3 | /**
4 | * 二叉树
5 | *
6 | * @author biezhi
7 | * @date 2018/6/24
8 | */
9 | public class BinaryTree {
10 |
11 | public int size() {
12 | return -1;
13 | }
14 |
15 | public int height(){
16 | return -1;
17 | }
18 |
19 | public int nodeNumbers(){
20 | return -1;
21 | }
22 |
23 | public int memoryBytes(){
24 | return -1;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/chapter_10/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_10;
2 |
3 | /**
4 | * 缩小变量的作用域
5 | *
6 | * @author biezhi
7 | * @date 2018/7/25
8 | */
9 | public class Example3 {
10 |
11 | public void method1() {
12 | String username = "abc";
13 | // String.format()
14 | System.out.println(method2(username));
15 | }
16 |
17 | public boolean method2(String username) {
18 | return null != username && username.length() > 6;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/chapter_04/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_04;
2 |
3 | /**
4 | * 相亲
5 | *
6 | * @author biezhi
7 | * @date 2018/6/27
8 | */
9 | public class Example2 {
10 |
11 | public static final int MIN_DEPOSIT = 100_000;
12 |
13 | private int searchDeposit(String userName) {
14 | return 2000;
15 | }
16 |
17 | public void invoke() {
18 | if (searchDeposit("os7blue") < MIN_DEPOSIT) {
19 | System.out.println("您预约的妹子已下线");
20 | }
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/chapter_07/Example9.java:
--------------------------------------------------------------------------------
1 | package chapter_07;
2 |
3 | import java.nio.file.Files;
4 | import java.nio.file.Paths;
5 |
6 | /**
7 | * 精确的描述方法的行为
8 | *
9 | * @author biezhi
10 | * @date 2018/7/7
11 | */
12 | public class Example9 {
13 |
14 | /**
15 | * 返回此文件中有多少换行("\n")
16 | */
17 | int countLines(String fileName) {
18 | try {
19 | return Files.readAllLines(Paths.get(fileName)).size();
20 | } catch (Exception e) {
21 | throw new RuntimeException(e);
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/chapter_06/Example6.java:
--------------------------------------------------------------------------------
1 | package chapter_06;
2 |
3 | /**
4 | * 公布可能的陷阱
5 | *
6 | * @author biezhi
7 | * @date 2018/7/6
8 | */
9 | public class Example6 {
10 |
11 | // 调用外部API发送邮件,1分钟后超时。
12 | void sendEmail(String to, String subject, String body) {
13 |
14 | }
15 |
16 | // 运行时间可以达到 O(标签数 * 标签深度),小心深层嵌套的输入
17 | void fixBrokenHtml(String html) {
18 |
19 | }
20 |
21 | /**
22 | * 这个文件包含一些辅助方法,为我们的文件系统提供了方便的接口。
23 | * 它处理了文件权限和一些其他的细节。
24 | */
25 | class BiezhiUtils {
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/chapter_08/README.md:
--------------------------------------------------------------------------------
1 | # 简化流程让代码易读
2 |
3 | | 编程结构 | 高层次程序流程是人如何变得不清晰的 |
4 | |-------|:--------:|
5 | | 线程 | 不清楚什么时候会执行代码 |
6 | | 信号量/中断处理程序 | 有些代码随时都有可能执行 |
7 | | 异常 | 可能会从多个函数向上冒泡的执行 |
8 | | 匿名函数 | 很难知道到底会执行什么代码,因为在编译器还未确定 |
9 |
10 | # 总结
11 |
12 | 1. 写一个比较时,把改变的值放在左边,把稳定的值放在右边
13 | 2. 可以重新排列 if else 代码块,优先处理正确的、简单的逻辑。
14 | 有时这些准则会冲突,当不冲突时,遵循这些经验法则。
15 | 3. 像三目运算符、do while循环经常会导致代码可读性变差。最好不要使用它们,
16 | 因为总是有更整洁的方式。
17 | 4. 嵌套的代码块需要花一些时间去理解。每层新的嵌套都会给读者“思维栈” push
18 | 一条数据。应该让它们变得“线性”,来避免深层嵌套。
19 | 5. 提早返回可以让代码更整洁。
--------------------------------------------------------------------------------
/src/main/java/chapter_02/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_02;
2 |
3 | /**
4 | * @author biezhi
5 | * @date 2018/6/24
6 | */
7 | public class Example2 {
8 |
9 | private int cap = 2333;
10 | private double weight = 1.5;
11 |
12 | public double before() {
13 | return cap >= 0 ? weight * (1 << cap) : weight / (1 << -cap);
14 | }
15 |
16 | public double after() {
17 | if (cap >= 0){
18 | return weight * (1 << cap);
19 | }
20 | return weight / (1 << -cap);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/chapter_06/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_06;
2 |
3 | /**
4 | * 记录你的思想
5 | *
6 | * @author biezhi
7 | * @date 2018/7/6
8 | */
9 | public class Example3 {
10 |
11 | /**
12 | * 出乎意料的是,对于这些数据用二叉树比 Map 快 40%
13 | *
14 | * 哈希运算的代价比左/右大得多
15 | */
16 | public void foo() {
17 |
18 | }
19 |
20 | /**
21 | * 作为整体可能会丢掉几个词。
22 | *
23 | * 这没问题,要 100% 解决太难了
24 | */
25 | public void bar() {
26 |
27 | }
28 |
29 | /**
30 | * 这个方法变得越来越乱
31 | *
32 | * 也许可以创建一个 foo 来帮助分解
33 | */
34 | public void boobar() {
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/chapter_10/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_10;
2 |
3 | /**
4 | * 减少控制流变量
5 | *
6 | * @author biezhi
7 | * @date 2018/7/25
8 | */
9 | public class Example2 {
10 |
11 | int foo = 10;
12 | int bar = 20;
13 |
14 | public void part1() {
15 | while (foo < bar) {
16 | if(!isDone()){
17 | break;
18 | }
19 | foo++;
20 | if (foo > bar) {
21 | continue;
22 | }
23 | }
24 | }
25 |
26 | private boolean isDone(){
27 | return false;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/chapter_07/Example12.java:
--------------------------------------------------------------------------------
1 | package chapter_07;
2 |
3 | import java.math.BigDecimal;
4 | import java.time.LocalDate;
5 |
6 | /**
7 | * 采用信息量高的词
8 | *
9 | * @author biezhi
10 | * @date 2018/7/7
11 | */
12 | public class Example12 {
13 |
14 | /**
15 | * 该类充当数据库的缓存层
16 | */
17 | class StoreAccounts {
18 |
19 | String username;
20 | String roleName;
21 | Integer score;
22 | LocalDate birthday;
23 | BigDecimal amount;
24 | // ...
25 | }
26 |
27 | /**
28 | * 规范化街道地址(删除多余的空格,简化词组。如将“Avenue”变为“Ave”)
29 | */
30 | public void cleanStreet() {
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/chapter_09/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_09;
2 |
3 | /**
4 | * 用作解释的变量
5 | *
6 | * @author biezhi
7 | * @date 2018/7/14
8 | */
9 | public class Example1 {
10 |
11 | public void part1() {
12 | String line = "hello : world";
13 | if ("hello".equals(line.split(":")[0].trim())) {
14 | // TODO
15 | }
16 | }
17 |
18 | public void part2() {
19 | String line = "hello : world";
20 | String hello = line.split(":")[0].trim();
21 | if ("hello".equals(hello)) {
22 | // TODO
23 | }
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/chapter_03/Example5.java:
--------------------------------------------------------------------------------
1 | package chapter_03;
2 |
3 | /**
4 | * 用具体的名字代替抽象的名字
5 | *
6 | * @author biezhi
7 | * @date 2018/6/24
8 | */
9 | public class Example5 {
10 |
11 | /**
12 | * VM options -DrunLocally=true
13 | */
14 | public void start() {
15 | String runLocally = System.getProperty("runLocally", "false");
16 | System.out.println("runLocally: " + runLocally);
17 |
18 | String extraLogging = System.getProperty("extraLogging", "false");
19 | }
20 |
21 | public static void main(String[] args) {
22 | new Example5().start();
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/chapter_06/README.md:
--------------------------------------------------------------------------------
1 | # 什么样的注释是好的
2 |
3 | | 标记 | 含义 |
4 | |-------|:--------:|
5 | | TODO | 等待处理的事情 |
6 | | FIXME | 已知无法运行的代码 |
7 | | HACK | 对一个问题不得不采用的简单粗暴的方案 |
8 | | XXX | 危险,这里有严重的问题 |
9 |
10 | ## 该写什么样的注释
11 |
12 | 注释的目的是帮助读代码的人了解作者在写代码时的思想。
13 |
14 | ## 什么地方不需要注释:
15 |
16 | - 能从代码本身中快速推断的事实
17 | - 用来装饰垃圾代码(比如拗口的方法名),实际上应该把名称修改好
18 |
19 | ## 记录你的想法
20 |
21 | - 为什么代码写成这样而不是另一个样子的内在理由(“指导性批注”)
22 | - 代码中的不足,使用像 TODO 或者 XXX 这样的标记
23 | - 常量背后的意义,为什么是这个值?
24 |
25 | ## 在读者的立场思考
26 |
27 | - 预料到代码中哪些部分会让读者说:“哎嘿?什么鬼” 给它们加上注释
28 | - 为小白意料之外的行为加注释
29 | - 在文件、类级别上使用“全局观”注释来解释所有的部分是如何一起工作的
30 | - 用注释总结代码块,让读者不会迷茫在细节里
31 |
--------------------------------------------------------------------------------
/src/main/java/chapter_14/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_14;
2 |
3 | import java.util.*;
4 |
5 | /**
6 | * 删除无用代码
7 | *
8 | * @author biezhi
9 | * @date 2018/9/24
10 | */
11 | public class Example3 {
12 |
13 | public Map readData(){
14 | Map result = new HashMap<>();
15 | result.put("title", i18n("title", "cn"));
16 | result.put("bannerText", i18n("bannerText", "cn"));
17 | result.put("copyright", i18n("copyright", "cn"));
18 |
19 | return result;
20 | }
21 |
22 | public String i18n(String key, String language){
23 | return "";
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/chapter_04/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_04;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * 范围
8 | *
9 | * @author biezhi
10 | * @date 2018/6/27
11 | */
12 | public class Example3 {
13 |
14 | private List ageRange(int minAge, int maxAge) {
15 | List list = new ArrayList<>(maxAge - minAge);
16 | for (int i = minAge; i < maxAge; i++) {
17 | list.add(i);
18 | }
19 | return list;
20 | }
21 |
22 | public void invoke() {
23 | List range = ageRange(20, 35);
24 | System.out.println(range);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/chapter_05/Example4.java:
--------------------------------------------------------------------------------
1 | package chapter_05;
2 |
3 | /**
4 | * 把声明按块组织起来
5 | *
6 | * @author biezhi
7 | * @date 2018/7/3
8 | */
9 | public class Example4 {
10 |
11 | interface RouteContext {
12 |
13 | // 读取Request信息
14 | String uri();
15 | String contentType();
16 | String header(String name);
17 | String cookie(String name);
18 | String pathString(String name);
19 |
20 | // 向Request写入数据
21 | RouteContext attribute(String key, Object value);
22 |
23 | // 向客户端发送数据
24 | void render(String view);
25 | RouteContext status(int status);
26 |
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/chapter_03/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_03;
2 |
3 | /**
4 | * 选择专业的词
5 | *
6 | * 找到更有表现力的词
7 | *
8 | * @author biezhi
9 | * @date 2018/6/24
10 | */
11 | public class Example1 {
12 |
13 | // downloadPage fetchPage
14 | public String getPage(String url) {
15 | // 抓取URL页面信息返回
16 | return "";
17 | }
18 |
19 | // 播放器
20 | static class Player {
21 |
22 | // 暂停播放
23 | public void pause(){
24 |
25 | }
26 |
27 | // 恢复播放
28 | public void resume(){
29 |
30 | }
31 |
32 | @Deprecated
33 | public void stop() {
34 |
35 | }
36 |
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/chapter_07/Example11.java:
--------------------------------------------------------------------------------
1 | package chapter_07;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * 声明代码的意图
7 | *
8 | * @author biezhi
9 | * @date 2018/7/7
10 | */
11 | public class Example11 {
12 | static class Product{
13 | Integer price;
14 | }
15 | public void displayProducts(List products){
16 | products.sort(this::compareProductByPrice);
17 |
18 | // 从高到低的显示每个商品的价格
19 | for (Product product: products) {
20 | displayPrice(product.price);
21 | }
22 | }
23 |
24 | private void displayPrice(Integer price) {
25 | }
26 |
27 | private int compareProductByPrice(Product p1, Product p2) {
28 | return p2.price.compareTo(p1.price);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/chapter_10/Example4.js:
--------------------------------------------------------------------------------
1 | // var submmitted = false; // 全局变量
2 |
3 | // var submit_form = function (form_name) {
4 | // if(submmitted) {
5 | // return; // 不能重复提交
6 | // }
7 | // // 向后端发送请求
8 | // // ...
9 | // submmitted = true;
10 | // };
11 |
12 | var submit_form = (function () {
13 | var submmitted = false; // 局部变量,只在闭包内生效
14 | return function (form_name) {
15 | if(submmitted){
16 | return;
17 | }
18 | submmitted = true;
19 | }
20 | }());
21 |
22 |
23 | var f = function () {
24 | // 定义 i 的时候没有使用 var 声明
25 | for (var i = 0; i < 10; i++){
26 | //
27 | }
28 | };
29 | f();
30 |
31 | console.log(i);
--------------------------------------------------------------------------------
/src/main/java/chapter_06/Example5.java:
--------------------------------------------------------------------------------
1 | package chapter_06;
2 |
3 | import java.util.Vector;
4 |
5 | /**
6 | * 给常量加注释
7 | *
8 | * @author biezhi
9 | * @date 2018/7/6
10 | */
11 | public class Example5 {
12 |
13 | // 只要它 >= 2 * CPU Core 就可以了
14 | private static final int NUM_THREADS = 8;
15 |
16 | // 添加一个限制,没有人可以订阅这么多
17 | private static final int MAX_RSS_SUBSCRIPTIONS = 1000;
18 |
19 | // 0.72 是经过计算的一个高质量参数
20 | private static final double IMAGE_QUALITY = 0.72D;
21 |
22 | static class Recorder {
23 |
24 | Vector data;
25 |
26 | void clear() {
27 | swap(data); // ??? 不是执行 data.clear() 么,什么鬼。。。
28 | }
29 |
30 | private void swap(Vector data) {
31 |
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/chapter_07/Example8.java:
--------------------------------------------------------------------------------
1 | package chapter_07;
2 |
3 | import java.util.HashMap;
4 | import javafx.util.Pair;
5 | import jdk.nashorn.internal.ir.RuntimeNode.Request;
6 |
7 | /**
8 | * 写出言简意赅的注释
9 | *
10 | * @author biezhi
11 | * @date 2018/7/6
12 | */
13 | public class Example8 {
14 |
15 | // 这里的 Integer 是分类类型
16 | // Pair 内部的第一个浮点数是得分
17 | // 第二个浮点数是权重
18 |
19 | // CategoryType -> (score, weight)
20 | HashMap> scoreMap;
21 |
22 | // 从当前线程 Request 中获取查询参数
23 | public void queryParam(Request request) {
24 |
25 | }
26 |
27 | // 根据我们是否已经爬过这个URL,给它一个不同的优先级。
28 | public void crawledURL1() {
29 |
30 | }
31 |
32 | // 优先考虑之前从未爬过的网址
33 | public void crawledURL2() {
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/chapter_03/Example4.java:
--------------------------------------------------------------------------------
1 | package chapter_03;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 |
6 | /**
7 | * 用前缀或后缀表达含义
8 | *
9 | * @author biezhi
10 | * @date 2018/6/24
11 | */
12 | public class Example4 {
13 |
14 | private static final int DEFAULT_PORT = 9000;
15 | private static final List DEFAULT_STATICS = Arrays.asList("/static", "/upload");
16 |
17 | // bad
18 | private String id = "af84ef845cd8";
19 | private String hexId = "af84ef845cd8";
20 |
21 | public void calcTime() {
22 | long startMs = System.currentTimeMillis();
23 | // do something
24 | long elapsed = System.currentTimeMillis() - startMs;
25 | System.out.println("耗时: " + elapsed + "ms");
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/chapter_11/Example5.js:
--------------------------------------------------------------------------------
1 | var max_results = get_cookie("max_results");
2 | // name1=value1; name2=value2;
3 | // var cookies = document.cookie.split(';');
4 | // for (var i = 0; i < cookies.length; i++) {
5 | // var c = cookies[i];
6 | // c = c.replace(/^[ ]+/, ''); // 移除多余的空格
7 | // if (c.indexOf('max_results') === 0) {
8 | // max_results = Number(c.substring(12, c.length));
9 | // }
10 | // }
11 |
12 | function get_cookie(key) {
13 | var cookies = document.cookie.split(';');
14 | for (var i = 0; i < cookies.length; i++) {
15 | var c = cookies[i];
16 | c = c.replace(/^[ ]+/, ''); // 移除多余的空格
17 | if (c.indexOf(key) === 0) {
18 | return c.substring(key.length + 1, c.length);
19 | }
20 | }
21 | return null;
22 | }
--------------------------------------------------------------------------------
/src/main/java/chapter_06/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_06;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * 什么不需要注释
7 | *
8 | * @author biezhi
9 | * @date 2018/7/6
10 | */
11 | public class Example1 {
12 |
13 | // 定义了一个账户类
14 | static class Account {
15 |
16 | // 构造器
17 | public Account() {
18 | }
19 |
20 | // 将利润设置为一个新值
21 | void setPorfit(double profit) {
22 |
23 | }
24 |
25 | // 返回账户的利润
26 | double getProfit() {
27 | return 2.9D;
28 | }
29 |
30 | }
31 |
32 | public void foo() {
33 | String line = "hello:world:2018";
34 |
35 | // 删除第二个 ":" 之后的元素
36 | String[] newLines = Arrays.copyOfRange(line.split(":"), 0, 2);
37 | String name = String.join(":", newLines);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/chapter_08/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_08;
2 |
3 | /**
4 | * 三目运算符
5 | *
6 | * @author biezhi
7 | * @date 2018/7/11
8 | */
9 | public class Example3 {
10 |
11 | int hour;
12 |
13 | public void part1() {
14 | String timeString = (hour >= 12) ? "pm" : "am";
15 |
16 | if(hour >= 12){
17 | timeString = "pm";
18 | } else {
19 | timeString = "am";
20 | }
21 | }
22 |
23 | public int part2() {
24 | int exponent = 20; // 计算出来的值
25 | int mantissa = -1; // 为了演示写死了
26 | if(exponent >= 0){
27 | return mantissa * (1 << exponent);
28 | }
29 | return mantissa / (1 << exponent);
30 | // return exponent >= 0 ? mantissa * (1 << exponent) :
31 | // mantissa / (1 << exponent);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/chapter_03/Example6.java:
--------------------------------------------------------------------------------
1 | package chapter_03;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | /**
7 | * 名字该多长
8 | *
9 | * @author biezhi
10 | * @date 2018/6/24
11 | */
12 | public class Example6 {
13 |
14 | private String newNavigationControllerWrappingViewControllerForDataSourceOfClass;
15 |
16 | private boolean debug;
17 |
18 | public void foo() {
19 | if (debug) {
20 | Map m = new HashMap<>();
21 | lookUpNamesNumbers(m);
22 | System.out.println(m);
23 | }
24 | }
25 |
26 | private void lookUpNamesNumbers(Map m) {
27 |
28 | }
29 |
30 | private final long cMaxFileSize = 1024 * 10L;
31 | private final long MAX_FILE_SIZE = 1024 * 10L;
32 |
33 | public void usePattern() {
34 | int offset_ = 10;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/chapter_08/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_08;
2 |
3 | /**
4 | * 条件语句中参数的顺序
5 | *
6 | * @author biezhi
7 | * @date 2018/7/11
8 | */
9 | public class Example1 {
10 |
11 | int length = 2018;
12 | long bytesReceived;
13 | long bytesExpected;
14 |
15 | public void part1() {
16 | if (length >= 2000) {
17 | System.out.println("你是一个现代程序员");
18 | }
19 | }
20 |
21 | public void part2() {
22 | if (2000 <= length) {
23 | System.out.println("你是一个现代程序员??");
24 | }
25 | }
26 |
27 | public void part3() {
28 | while (bytesReceived < bytesExpected) {
29 | System.out.println("请继续接收");
30 | }
31 | }
32 |
33 | public void part4() {
34 | while (bytesExpected > bytesReceived) {
35 | System.out.println("请继续接收");
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/chapter_02/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_02;
2 |
3 | import java.util.LinkedList;
4 | import java.util.Queue;
5 |
6 | /**
7 | * @author biezhi
8 | * @date 2018/6/24
9 | */
10 | public class Example1 {
11 |
12 | Queue nodes = new LinkedList();
13 |
14 | public Example1() {
15 | nodes.add(new Node());
16 | nodes.add(new Node());
17 | }
18 |
19 | public void snippet1() {
20 | for (Node node = nodes.peek(); node != null; node = node.next()) {
21 | System.out.println(node.data());
22 | }
23 | }
24 |
25 | public void snippet2() {
26 | Node node = nodes.peek();
27 | if (node == null) return;
28 | while (node.next() != null) {
29 | System.out.println(node.data());
30 | node = node.next();
31 | }
32 | if (node != null) System.out.println(node.data());
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/chapter_08/Example4.java:
--------------------------------------------------------------------------------
1 | package chapter_08;
2 |
3 | /**
4 | * 避免用 do while 循环
5 | *
6 | * @author biezhi
7 | * @date 2018/7/11
8 | */
9 | public class Example4 {
10 |
11 | int hour;
12 |
13 | class Node {
14 | String name;
15 | Node next;
16 | }
17 |
18 | // public boolean listHasNode(Node node, String name, int maxLength) {
19 | // do {
20 | // if (node.name.equals(name))
21 | // return true;
22 | // node = node.next;
23 | // } while (node != null && --maxLength > 0);
24 | // return false;
25 | // }
26 |
27 | public boolean listHasNode(Node node, String name, int maxLength) {
28 | while (node != null && maxLength-- > 0){
29 | if (node.name.equals(name))
30 | return true;
31 | node = node.next;
32 | }
33 | return false;
34 | }
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/chapter_09/Example4.java:
--------------------------------------------------------------------------------
1 | package chapter_09;
2 |
3 | /**
4 | * 与复杂的逻辑斗争
5 | *
6 | * @author biezhi
7 | * @date 2018/7/14
8 | */
9 | public class Example4 {
10 |
11 | class Range{
12 | int begin;
13 | int end;
14 |
15 | // 如:(0, 5) 会和 (3, 8) 重合
16 | // (0, 2) (2,4)
17 | boolean overlapsWith(Range other){
18 | // 检查自己的任意端点是否在 other 的范围之内
19 | // return (begin >= other.begin && begin <= other.end) ||
20 | // (end >= other.begin && end <= other.end);
21 | // return (begin >= other.begin && begin < other.end) ||
22 | // (end > other.begin && end <= other.end) ||
23 | // (begin <= other.begin && end >= other.end);
24 | if(other.end <= begin) return false;
25 | if(other.begin >= end) return false;
26 | return true;
27 | }
28 | }
29 |
30 |
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/chapter_12/Example1.js:
--------------------------------------------------------------------------------
1 | var vote_change = function (old_vote, new_vote) {
2 | var weight = get_weight();
3 | // if (new_vote !== old_vote) {
4 | // if (new_vote === 'Up') {
5 | // weight += (old_vote === 'Up' ? 2 : 1);
6 | // } else if (new_vote === 'Down') {
7 | // weight -= (old_vote === 'Up' ? 2 : 1);
8 | // } else if (new_vote === '') {
9 | // weight += (old_vote === 'Up' ? -1 : 1);
10 | // }
11 | // set_weight(weight);
12 | // }
13 | weight -= get_vote_value(old_vote);
14 | weight += get_vote_value(new_vote);
15 |
16 | set_weight(weight);
17 | };
18 |
19 | function get_vote_value(vote) {
20 | if(vote === 'Up'){
21 | return +1;
22 | }
23 | if(vote === 'Down'){
24 | return -1;
25 | }
26 | return 0;
27 | }
28 |
29 | function get_weight() {
30 | }
31 | function set_weight(weight) {
32 | }
--------------------------------------------------------------------------------
/src/main/java/chapter_09/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_09;
2 |
3 | /**
4 | * 使用德摩根定理
5 | * 滥用短路逻辑
6 | *
7 | * @author biezhi
8 | * @date 2018/7/14
9 | */
10 | public class Example3 {
11 |
12 | /**
13 | * 1) not (a or b or c) <=> (not a) and (not b) and (not c)
14 | * 2) not (a and b and c) <=> (not a) or (not b) or (not c)
15 | */
16 | public void part1(boolean fileExists, boolean isProtected) {
17 | // if (!(fileExists && !isProtected)) {
18 | // throw new RuntimeException("对不起,无法读取该文件");
19 | // }
20 | if (!fileExists || isProtected) {
21 | throw new RuntimeException("对不起,无法读取该文件");
22 | }
23 | }
24 |
25 |
26 | public void part2() {
27 | // assert((!(bucket = findBucket(key)) && bucket->isOccupied()))
28 | // bucket = findBucket(key)
29 | // if bucket != null {
30 | // assert bucket.isOccupied
31 | // }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/chapter_13/Example2.js:
--------------------------------------------------------------------------------
1 | // 尝试搜索:王爵的技术小黑屋
2 | // 尝试搜索:流行编程字体
3 | // 尝试搜索:Github 使用技巧
4 |
5 | //
6 |
7 | // var show_next_tip = function(){
8 | // var num_tips = $('.tip').size();
9 | // var show_tip = $('.tip:visible');
10 | //
11 | // var show_tip_num = Number(show_tip.attr('id').slice(4));
12 | // if(show_tip_num === num_tips) {
13 | // $('#tip-1').show();
14 | // } else {
15 | // $('#tip-' + (show_tip_num + 1)).show();
16 | // }
17 | // show_tip.hide();
18 | // };
19 |
20 | var show_next_tip = function(){
21 | // 隐藏当前显示的搜索记录
22 | var cur_tip = $('.tip:visited').hide();
23 | // 找到下一个搜索记录
24 | var next_tip = cur_tip.next('.tip');
25 | if(next_tip.size() === 0){
26 | next_tip = $('.tip:first');
27 | }
28 | next_tip.show();
29 | };
--------------------------------------------------------------------------------
/src/main/java/chapter_06/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_06;
2 |
3 | /**
4 | * 不用为了注释而注释
5 | * 不要给不好的名字加注释——应该把名字改好
6 | *
7 | * @author biezhi
8 | * @date 2018/7/6
9 | */
10 | public class Example2 {
11 |
12 | static class Node {
13 |
14 | String name;
15 | }
16 |
17 | /**
18 | * 查找具有给定名称的节点或者返回一个null
19 | *
20 | * 1. 如果深度 <= 0, 只检查子树
21 | * 2. 如果深度 == N, 只检查子树和 N 级以下
22 | */
23 | Node findNodeInSubTree(Node subTree, String name, int depth) {
24 | return null;
25 | }
26 |
27 | /**
28 | * 对请求中的回复状态做限制
29 | *
30 | * 例如返回的项目数或总字节大小等。
31 | */
32 | void cleanReply(String request, String reply) {
33 |
34 | }
35 |
36 | /**
37 | * 对请求做一个限制,确保回复状态符合 “次数/字节” 等等
38 | * @param request
39 | * @param reply
40 | */
41 | void enforceLimitsForRequest(String request, String reply){
42 |
43 | }
44 |
45 | /**
46 | * 释放本地的 registryKey,不会修改注册中心的实际数据
47 | */
48 | void releaseRegistry(String registryKey) {
49 |
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/chapter_10/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_10;
2 |
3 | import java.time.LocalDateTime;
4 | import java.util.Arrays;
5 | import java.util.List;
6 | import java.util.function.BiConsumer;
7 |
8 | /**
9 | * 减少变量
10 | *
11 | * @author biezhi
12 | * @date 2018/7/21
13 | */
14 | public class Example1 {
15 |
16 | class Message {
17 | LocalDateTime lastViewTime;
18 | }
19 |
20 | public void part1(Message rootMessage) {
21 | rootMessage.lastViewTime = LocalDateTime.now();
22 | }
23 |
24 |
25 | public void part2() {
26 | BiConsumer, Integer> consumer = (array, valueToRemove) -> {
27 | for (int i = 0; i < array.size(); i++) {
28 | if (array.get(i).equals(valueToRemove)) {
29 | array.remove(i);
30 | break;
31 | }
32 | }
33 | };
34 | consumer.accept(Arrays.asList(1, 2, 3), 2);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/chapter_09/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_09;
2 |
3 | /**
4 | * 总结变量
5 | *
6 | * @author biezhi
7 | * @date 2018/7/14
8 | */
9 | public class Example2 {
10 |
11 | class User {
12 |
13 | long id;
14 | }
15 |
16 | class Request {
17 |
18 | User user;
19 | }
20 |
21 | class Document {
22 |
23 | long ownerId;
24 | }
25 |
26 | public void part1(Request request, Document document) {
27 | if (request.user.id == document.ownerId) {
28 | // 允许该用户编辑文档
29 | }
30 | if (request.user.id != document.ownerId) {
31 | // 文档只读
32 | }
33 | }
34 |
35 | public void part2(Request request, Document document) {
36 | boolean userOwnsDocument = (request.user.id == document.ownerId);
37 | if (userOwnsDocument) {
38 | // 允许该用户编辑文档
39 | }
40 | if (!userOwnsDocument) {
41 | // 文档只读
42 | }
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/chapter_09/Example6.java:
--------------------------------------------------------------------------------
1 | package chapter_09;
2 |
3 | import org.apache.commons.beanutils.BeanUtils;
4 |
5 | /**
6 | * 简化表达式的创意方法
7 | *
8 | * @author biezhi
9 | * @date 2018/7/14
10 | */
11 | public class Example6 {
12 |
13 | class Stats {
14 |
15 | long totalMemory;
16 | long freeMemory;
17 | long swapMemory;
18 | int numProcesses;
19 | String statusString;
20 | }
21 |
22 | public void addStats(Stats addFrom, Stats addTo) {
23 | addTo.totalMemory = addFrom.totalMemory + addTo.totalMemory;
24 | addTo.freeMemory = addFrom.freeMemory + addTo.freeMemory;
25 | addTo.swapMemory = addFrom.swapMemory + addTo.swapMemory;
26 | addTo.swapMemory = addFrom.swapMemory + addTo.swapMemory;
27 | addTo.statusString = addFrom.statusString + addTo.statusString;
28 | addTo.numProcesses = addFrom.numProcesses + addTo.numProcesses;
29 | // ...
30 | // BeanUtils.copyProperties();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/chapter_11/Example1.js:
--------------------------------------------------------------------------------
1 | // 返回 'array' 中哪个位置最接近给定的经纬度
2 | // 将地球塑造成一个完美的球体。
3 | var findClosestLocation = function (lat, lng, array) {
4 | var closest;
5 | var closest_dist = Number.MAX_VALUE;
6 | for (var i = 0; i < array.length; i++) {
7 |
8 | var dist = spherical_distance(lat, lng, array[i].latitude, array[i].longitude);
9 | if (dist < closest_dist) {
10 | closest = array[i];
11 | closest_dist = dist;
12 | }
13 | }
14 | return closest;
15 | };
16 |
17 | function spherical_distance(lat, lng, latitude, longitude) {
18 | // 将两个点转换为弧度
19 | var lat_rad = radians(lat);
20 | var lng_rad = radians(lng);
21 | var lat2_rad = radians(latitude);
22 | var lng2_rad = radians(longitude);
23 |
24 | // 使用'球面三角形的余弦定理'公式
25 | return Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) +
26 | Math.cos(lat_rad) * Math.cos(lat2_rad) +
27 | Math.cos(lng2_rad - lng_rad));
28 | }
29 |
30 | function radians(point) {
31 | return 1;
32 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 编写可读代码的艺术
2 |
3 | 编写高质量的代码是程序员追求的目标,这个视频以《编写可读代码的艺术》为蓝本,
4 | 使用 Java 语言讲解其中的优化手段。
5 |
6 | ## 课程地址
7 |
8 | - [Youtube 频道](https://www.youtube.com/c/biezhi)
9 | - [Bilibili](https://space.bilibili.com/33165125)
10 |
11 | ## 章节
12 |
13 | - [01. 课程介绍](https://youtu.be/SNYwZ1l9blc)
14 | - [02. 写让人理解的代码](https://youtu.be/GYTgrSQO8fs)
15 | - [03. 把信息装到名字里](https://youtu.be/aEj9YF8uxts)
16 | - [04. 让人不会误解的名字](https://youtu.be/ssuSlE3gSxc)
17 | - [05. 写代码也需要审美?](https://youtu.be/X6OIaGhCt1s)
18 | - [06. 什么样的注释是好的?](https://youtu.be/C1g0xLfwD74)
19 | - [07. 写言简意赅的注释](https://youtu.be/yR2aXO0doRk)
20 | - [08. 简化流程让代码易读](https://youtu.be/v6A231LCdAQ)
21 | - [09. 拆分又臭又长的表达式](https://youtu.be/7_0ZhB0bJV0)
22 | - [10. 变量和可读性](https://youtu.be/K8oognOKIlA)
23 | - [11. 抽取无关的代码](https://youtu.be/no8M8C1HNuI)
24 | - [12. 一次只干一件事](https://youtu.be/atrR3_h-AhA)
25 | - [13. 把想法变成代码](https://youtu.be/b_CiksFfIvI)
26 | - [14. 少写点代码](https://youtu.be/yuRAvtmwgzY)
27 | - [15. 测试和可读性](#) - 待更新
28 | - [16. 你的最终考验](#) - 待更新
29 |
30 | ## License
31 |
32 | [BSD3](LICENSE)
33 |
34 |
--------------------------------------------------------------------------------
/src/main/java/chapter_05/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_05;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * 为什么审美是重要的
7 | *
8 | * @author biezhi
9 | * @date 2018/7/3
10 | */
11 | public class Example1 {
12 |
13 | static abstract class StatsKeeper1 {
14 | // A class for keeping track of a series of doubles
15 | abstract void add(double d); // and methods for quick statistics about them
16 | private int count; /* how many so far
17 | */ public abstract double avgerage();
18 | private double minimum;
19 | private List pastItems
20 | ; double maximum;
21 |
22 | }
23 |
24 | // A class for keeping track of a series of doubles
25 | // and methods for quick statistics about them
26 | static abstract class StatsKeeper2 {
27 |
28 | abstract void add(double d);
29 | abstract double avgerage();
30 |
31 | private List pastItems;
32 | private int count; // how many so far
33 |
34 | private double minimum;
35 | private double maximum;
36 |
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/chapter_14/Example4.java:
--------------------------------------------------------------------------------
1 | package chapter_14;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.HashSet;
6 | import java.util.List;
7 | import java.util.stream.Collectors;
8 |
9 | import static java.util.stream.Collectors.toList;
10 |
11 | /**
12 | * 熟悉标准库
13 | *
14 | * @author biezhi
15 | * @date 2018/9/24
16 | */
17 | public class Example4 {
18 |
19 | private List list = Arrays.asList(2, 3, 3, 3);
20 |
21 | // public List unique(List elements) {
22 | // List result = new ArrayList<>();
23 | // for (Integer element : elements) {
24 | // if (!result.contains(element)) {
25 | // result.add(element);
26 | // }
27 | // }
28 | // return result;
29 | // }
30 |
31 | // public List unique(List elements) {
32 | // return new ArrayList<>(new HashSet<>(elements));
33 | // }
34 |
35 | public List unique(List elements) {
36 | return elements.stream().distinct().collect(toList());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/chapter_11/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_11;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.File;
5 | import java.io.FileReader;
6 | import java.io.IOException;
7 |
8 | /**
9 | * 纯工具代码
10 | *
11 | * @author biezhi
12 | * @date 2018/8/7
13 | */
14 | public class Example2 {
15 |
16 | public void foo(String fileName) {
17 | try {
18 | System.out.println(readFileToString(fileName));
19 | // TODO
20 | } catch (Exception e) {
21 | // Exception
22 | }
23 | }
24 |
25 | public String readFileToString(String filePath) throws IOException {
26 | StringBuilder currentLines = new StringBuilder();
27 | File file = new File(filePath);
28 | FileReader fr = new FileReader(file);
29 | BufferedReader bufferedReader = new BufferedReader(fr);
30 | String sCurrentLine;
31 | while ((sCurrentLine = bufferedReader.readLine()) != null) {
32 | currentLines.append(sCurrentLine).append("\n");
33 | }
34 | return currentLines.toString();
35 | }
36 | }
--------------------------------------------------------------------------------
/src/main/java/chapter_02/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_02;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | /**
7 | * @author biezhi
8 | * @date 2018/6/24
9 | */
10 | public class Example3 {
11 |
12 | private Map coderMap = new HashMap();
13 |
14 | public Example3() {
15 | coderMap.put("biezhi", new Coder(true));
16 | coderMap.put("80k", new Coder(false));
17 | }
18 |
19 | private Coder findCoder(String key) {
20 | return coderMap.get(key);
21 | }
22 |
23 | public void before() {
24 | Coder coder;
25 | boolean hasGirlFriend = (null != (coder = findCoder("biezhi"))) && coder.hasGirlFriend();
26 | System.out.println("是否有女朋友: " + hasGirlFriend);
27 | }
28 |
29 | public void after() {
30 | Coder coder = this.findCoder("biezhi");
31 | if(null != coder){
32 | System.out.println("是否有女朋友: " + coder.hasGirlFriend());
33 | }
34 | }
35 |
36 | public static void main(String[] args) {
37 | new Example3().before();
38 | new Example3().after();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | io.github.biezhi
8 | write-readable-code
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | commons-beanutils
14 | commons-beanutils
15 | 1.9.3
16 |
17 |
18 |
19 |
20 |
21 |
22 | org.apache.maven.plugins
23 | maven-compiler-plugin
24 |
25 | 1.8
26 | 1.8
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/main/java/chapter_14/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_14;
2 |
3 | /**
4 | * 缓存设计
5 | *
6 | * 读取 a.txt
7 | * 读取 a.txt
8 | * 读取 a.txt
9 | * 读取 b.txt
10 | * 读取 b.txt
11 | * 读取 c.txt
12 | * 读取 d.txt
13 | * 读取 d.txt
14 | *
15 | * @author biezhi
16 | * @date 2018/9/24
17 | */
18 | public class Example2 {
19 |
20 | private DiskText lastUsed;
21 |
22 | // 加载磁盘文件
23 | public DiskText loadDiskText(String key) {
24 | // 从本地加载
25 | return new DiskText(key, "");
26 | }
27 |
28 | // 根据 key 获取磁盘文件
29 | public DiskText lookUp(String key) {
30 | if (lastUsed == null || !lastUsed.key().equals(key)) {
31 | lastUsed = loadDiskText(key);
32 | }
33 | return lastUsed;
34 | }
35 |
36 | class DiskText {
37 | private String key;
38 | private String value;
39 |
40 | public DiskText(String key, String value) {
41 | this.key = key;
42 | this.value = value;
43 | }
44 |
45 | public String value() {
46 | return value;
47 | }
48 |
49 | public String key() {
50 | return key;
51 | }
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/src/main/java/chapter_06/Example7.java:
--------------------------------------------------------------------------------
1 | package chapter_06;
2 |
3 | import java.util.Arrays;
4 | import java.util.HashMap;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | /**
9 | * 总结性注释
10 | *
11 | * @author biezhi
12 | * @date 2018/7/6
13 | */
14 | public class Example7 {
15 |
16 | private List customers = Arrays.asList(1L, 3L, 45L, 62L, 98L);
17 | private Map> allSales = new HashMap<>();
18 |
19 | static class Sale {
20 |
21 | Long recipient;
22 | }
23 |
24 | public void foo() {
25 | // 找到客户购买的所有商品
26 | for (Long customerId: customers) {
27 | for (Sale sale: allSales.get(customerId)) {
28 | if (sale.recipient.equals(customerId)) {
29 | // do something
30 | }
31 | }
32 | }
33 | }
34 |
35 | public void generateUserReport() {
36 | // 获取当前用户的锁
37 | // .... 省略一部分代码
38 |
39 | // 从数据库中读取用户的信息
40 | // .... 省略一部分代码
41 |
42 | // 将信息写入到文件
43 | // .... 省略一部分代码
44 |
45 | // 释放当前用户的锁
46 | }
47 |
48 | // 1. 不管你心里在想什么,先把它记录下来
49 | // 2. 读一下这段注释,看看它有什么需要改进的
50 | // 3. 不断改进
51 |
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/chapter_09/Example5.js:
--------------------------------------------------------------------------------
1 | // var update_highlight = function (message_num) {
2 | // if ($("#vote_value" + message_num).html() === "Up") {
3 | // $("thumbs_up" + message_num).addClass('highlighted');
4 | // $("thumbs_down" + message_num).removeClass('highlighted');
5 | // } else if ($("#vote_value" + message_num).html() === "Down") {
6 | // $("thumbs_up" + message_num).removeClass('highlighted');
7 | // $("thumbs_down" + message_num).addClass('highlighted');
8 | // } else {
9 | // $("thumbs_up" + message_num).removeClass('highlighted');
10 | // $("thumbs_down" + message_num).removeClass('highlighted');
11 | // }
12 | // };
13 |
14 | var update_highlight = function (message_num) {
15 | var thumbs_up = $("thumbs_up" + message_num);
16 | var thumbs_down = $("thumbs_down" + message_num);
17 | var vote_value = $("#vote_value" + message_num).html();
18 | var hi = 'highlighted';
19 |
20 | if (vote_value === "Up") {
21 | thumbs_up.addClass(hi);
22 | thumbs_down.removeClass(hi);
23 | } else if (vote_value === "Down") {
24 | thumbs_up.removeClass(hi);
25 | thumbs_down.addClass(hi);
26 | } else {
27 | thumbs_up.removeClass(hi);
28 | thumbs_down.removeClass(hi);
29 | }
30 | };
--------------------------------------------------------------------------------
/src/main/java/chapter_11/Example6.java:
--------------------------------------------------------------------------------
1 | package chapter_11;
2 |
3 | import java.util.Base64;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | /**
8 | * 按需重构接口
9 | *
10 | * @author biezhi
11 | * @date 2018/8/13
12 | */
13 | public class Example6 {
14 |
15 | class Cipher {
16 | String method;
17 | String key;
18 |
19 | public Cipher(String method, String key) {
20 | this.method = method;
21 | this.key = key;
22 | }
23 |
24 | public byte[] update(String str) {
25 | return str.getBytes();
26 | }
27 |
28 | }
29 |
30 | private String toJson(Map map) {
31 | return null;
32 | }
33 |
34 | public void foo() {
35 | Map map = new HashMap<>();
36 | map.put("username", "biezhi");
37 | map.put("password", "123456");
38 |
39 | String url = "http://exmaple.com/?user_info=" + urlSafeEncrypt(map);
40 | // ...
41 | }
42 |
43 | private String urlSafeEncrypt(Map map){
44 | String json = toJson(map);
45 | Cipher cipher = new Cipher("aes_256", "pas5#w0rd");
46 | byte[] encryptedBytes = cipher.update(json);
47 | return Base64.getEncoder().encodeToString(encryptedBytes);
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/chapter_08/Example6.java:
--------------------------------------------------------------------------------
1 | package chapter_08;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 |
6 | /**
7 | * 减少循环嵌套
8 | *
9 | * @author biezhi
10 | * @date 2018/7/11
11 | */
12 | public class Example6 {
13 |
14 | class User {
15 | String name;
16 |
17 | public User(String name) {
18 | this.name = name;
19 | }
20 | }
21 |
22 | // public void foo() {
23 | // List result = Arrays.asList(new User("jack"),
24 | // new User("biezhi"));
25 | //
26 | // int notNullCount = 0;
27 | // for (User user: result) {
28 | // if (user != null) {
29 | // notNullCount++;
30 | // if (user.name != null) {
31 | // System.out.println(user.name);
32 | // }
33 | // }
34 | // }
35 | //
36 | // }
37 |
38 | public void bar() {
39 | List result = Arrays.asList(new User("jack"),
40 | new User("biezhi"));
41 |
42 | int notNullCount = 0;
43 | for (User user : result) {
44 | if (null == user) {
45 | continue;
46 | }
47 | notNullCount++;
48 | if (user.name != null) {
49 | System.out.println(user.name);
50 | }
51 | }
52 |
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/chapter_03/README.md:
--------------------------------------------------------------------------------
1 | # 把信息装到名字里
2 |
3 | ## 有表现力的词
4 |
5 | | 单词 | 更多选择 |
6 | |-------|:--------:|
7 | | send | deliver、dispatch、announce、distribute、route |
8 | | find | search、extract、locate、recover |
9 | | start | launch、create、begin、open |
10 | | make | create、set up、build、generate、compose、add、new |
11 |
12 | ## 带单位的命名
13 |
14 | | 参数或变量 | 带单位的命名 |
15 | |-------|:--------:|
16 | | start(int delay) | delay -> delaySecs |
17 | | createCache(int size) | size -> sizeMB |
18 | | throttleDownload(float limit) | limit -> maxKB |
19 | | setHeight(float height) | height -> heightCM |
20 |
21 | ## 给名字附加额外信息
22 |
23 | | 场景 | 变量名 | 更好的名字 |
24 | |-------|:--------:|:-------:|
25 | | 一个纯文本的密码,需要加密后才可以使用 | password | plaintextPassword |
26 | | 一条用户评论,需要转义后显示 | comment | unescapedComment |
27 | | 已转化为UTF-8的HTML文本 | html | htmlUtf8 |
28 | | 以"URL"方式编码的输入数据 | data | dataURLEncode |
29 |
30 | **[谷歌代码规范](https://github.com/google/styleguide) | [中文](http://zh-google-styleguide.readthedocs.io/en/latest/)**
31 |
32 | - [Java 代码规范](https://google.github.io/styleguide/javaguide.html)
33 | - [C++ 代码规范](https://google.github.io/styleguide/cppguide.html)
34 | - [Python 代码规范](https://github.com/google/styleguide/blob/gh-pages/pyguide.md)
35 | - [JavaScript 代码规范](https://google.github.io/styleguide/jsguide.html)
36 |
37 | ## 总结
38 |
39 | 1. 使用专业的词
40 | 2. 避免使用空泛的词
41 | 3. 给变量名带上附加信息
42 | 4. 为作用域更大的变量起一个长的名字
43 | 5. 有目的的使用大小写和下划线
--------------------------------------------------------------------------------
/src/main/java/chapter_11/Example4.java:
--------------------------------------------------------------------------------
1 | package chapter_11;
2 |
3 | import java.time.LocalDate;
4 |
5 | /**
6 | * 项目专有的功能
7 | *
8 | * @author biezhi
9 | * @date 2018/8/13
10 | */
11 | public class Example4 {
12 |
13 | class Request {
14 | String param(String key) {
15 | return "";
16 | }
17 | }
18 |
19 | static class Business {
20 | String name;
21 | String url;
22 | LocalDate created;
23 |
24 | public void save() {
25 | }
26 | }
27 |
28 | public void part1(Request request) {
29 | Business business = new Business();
30 | business.name = request.param("name");
31 |
32 | business.url = "/biz/" + makePrettyURL(business);
33 | business.created = LocalDate.now();
34 | business.save();
35 | }
36 |
37 | private String makePrettyURL(Business business) {
38 | String urlPathName = business.name.toLowerCase();
39 | urlPathName = urlPathName.replaceAll("[\\.,\\']", "");
40 | urlPathName = urlPathName.replaceAll("[^a-z0-9]+", "-");
41 | if (urlPathName.charAt(0) == '-') {
42 | urlPathName = urlPathName.substring(1);
43 | }
44 | if (urlPathName.charAt(urlPathName.length() - 1) == '-') {
45 | urlPathName = urlPathName.substring(0, urlPathName.length() - 1);
46 | }
47 | return urlPathName;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/chapter_05/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_05;
2 |
3 | import java.util.Map;
4 |
5 | /**
6 | * 在需要时使用对齐
7 | *
8 | * @author biezhi
9 | * @date 2018/7/3
10 | */
11 | public class Example3 {
12 |
13 | private Request request = new Request();
14 |
15 | static class Request {
16 | Request GET;
17 | Request POST;
18 | private Map values;
19 |
20 | public String get(String key) {
21 | return values.get(key);
22 | }
23 | }
24 |
25 | public void part1() {
26 | // 从 POST 中获取数据
27 | String company = request.POST.get("company");
28 | String kindergarten = request.POST.get("kindergarten");
29 | String subwayStation = request.POST.get("subwayStation");
30 | String zoo = request.POST.get("zoo");
31 |
32 | }
33 |
34 | public void part2() {
35 | // 从 POST 中获取数据
36 | String company = request.POST.get("company");
37 | String kindergarten = request.POST.get("kindergarten");
38 | String subwayStation = request.POST.get("subwayStation");
39 | String zoo = request.POST.get("zoo");
40 |
41 | if (null != company) { /* company */}
42 | if (null != subwayStation) { /* subwayStation // 这不是去幼儿园的车?*/}
43 | if (null != zoo) { /* zoo */}
44 | if (null != kindergarten) { /* kindergarten // 为什么我在幼儿园? */}
45 | }
46 |
47 | }
--------------------------------------------------------------------------------
/src/main/java/chapter_08/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_08;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 |
6 | /**
7 | * if else 块的顺序
8 | *
9 | * @author biezhi
10 | * @date 2018/7/11
11 | */
12 | public class Example2 {
13 |
14 | boolean a, b;
15 |
16 | public void part1() {
17 | // if (a == b) {
18 | // System.out.println("有钱人");
19 | // } else {
20 | // System.out.println("没钱的肥宅");
21 | // }
22 | if (a != b) {
23 | System.out.println("没钱的肥宅");
24 | } else {
25 | System.out.println("有钱人");
26 | }
27 | }
28 |
29 | class Request {
30 | boolean hasParam(String key) {
31 | return false;
32 | }
33 | }
34 |
35 | class Response {
36 | void writeJSON(Object bean) {
37 |
38 | }
39 | }
40 |
41 | public void part2(Request request, Response response) {
42 |
43 | List items = Arrays.asList("hello", "world");
44 |
45 | // if (!request.hasParam("biezhi")) {
46 | // response.writeJSON(items);
47 | // } else {
48 | // for (String item: items) {
49 | // // TODO
50 | // }
51 | // }
52 | if (request.hasParam("biezhi")) {
53 | for (String item: items) {
54 | // TODO
55 | }
56 | } else {
57 | response.writeJSON(items);
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/chapter_13/Example1.java:
--------------------------------------------------------------------------------
1 | package chapter_13;
2 |
3 | /**
4 | * 清楚的描述逻辑
5 | *
6 | * @author biezhi
7 | * @date 2018/9/1
8 | */
9 | public class Example1 {
10 |
11 | private boolean isAdminRequest(){
12 | return false;
13 | }
14 |
15 | private String noAuthorized(){
16 | return "authorized.html";
17 | }
18 |
19 | class Session {
20 |
21 | public String getAttribute(String key) {
22 | return "";
23 | }
24 | }
25 | class Document {
26 | String username;
27 | }
28 |
29 | // public String part1(Document document, Session session){
30 | // boolean isAdmin = isAdminRequest();
31 | // if(null != document){
32 | // if(!isAdmin && document.username != session.getAttribute("username")){
33 | // return noAuthorized();
34 | // }
35 | // } else {
36 | // if(!isAdmin) {
37 | // return noAuthorized();
38 | // }
39 | // }
40 | // // 渲染正常页面
41 | // return "biezhi.html";
42 | // }
43 |
44 | public String part2(Document document, Session session){
45 | boolean isAdmin = isAdminRequest();
46 | if(isAdmin){
47 | // 获取信息
48 | } else if(document.username.equals(session.getAttribute("username"))){
49 | // 获取信息
50 | } else {
51 | return noAuthorized();
52 | }
53 | // 渲染正常页面
54 | return "biezhi.html";
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/chapter_03/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_03;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.util.function.Function;
6 |
7 | /**
8 | * 避免tmp和retval这样泛泛的名字
9 | *
10 | * @author biezhi
11 | * @date 2018/6/24
12 | */
13 | public class Example2 {
14 |
15 | public void before() {
16 | // Function euclideanNorm = v -> {
17 | // double retval = 0;
18 | // for (int i = 0; i < v.length; i++)
19 | // retval += v[i] * v[i];
20 | // return Math.sqrt(retval);
21 | // };
22 | //
23 | // int[] numbs = {1, 2, 3, 5};
24 | // Double apply = euclideanNorm.apply(numbs);
25 | // System.out.println(apply);
26 | }
27 |
28 | public void after() {
29 | Function euclideanNorm = v -> {
30 | double sumSquares = 0;
31 | for (int i = 0; i < v.length; i++)
32 | sumSquares += v[i] * v[i];
33 | return Math.sqrt(sumSquares);
34 | };
35 |
36 | int[] numbs = {1, 2, 3, 5};
37 | Double apply = euclideanNorm.apply(numbs);
38 | System.out.println(apply);
39 | }
40 |
41 | public void numberSwap(int right, int left){
42 | int tmp = right;
43 | right = left;
44 | left = tmp;
45 | }
46 |
47 | public void tempUser() throws IOException {
48 | // String tmp = user.getUserName();
49 |
50 | Files.createTempFile("tmp_file", ".txt");
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/chapter_10/Example7.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
16 |
17 |
49 |
50 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, 王爵nice
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/src/main/java/chapter_03/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_03;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * 循环迭代器
8 | *
9 | * 用具体的名字代替抽象的名字
10 | *
11 | * @author biezhi
12 | * @date 2018/6/24
13 | */
14 | public class Example3 {
15 |
16 | static class Club {
17 |
18 | public List members() {
19 | return new ArrayList<>();
20 | }
21 | }
22 |
23 | public void before() {
24 | // List users = new ArrayList<>();
25 | // List clubs = new ArrayList<>();
26 | //
27 | // for (int i = 0; i < clubs.size(); i++) {
28 | // for (int j = 0; j < clubs.get(0).members().size(); j++) {
29 | // for (int k = 0; k < users.size(); k++) {
30 | // if (clubs.get(i).members().get(k) == users.get(j)) {
31 | // System.out.println("用户 [" + j + "] 在俱乐部 [" + i + "]");
32 | // }
33 | // }
34 | // }
35 | // }
36 |
37 | }
38 |
39 | public void after() {
40 | List users = new ArrayList<>();
41 | List clubs = new ArrayList<>();
42 |
43 | for (int ci = 0; ci < clubs.size(); ci++) {
44 | for (int mi = 0; mi < clubs.get(0).members().size(); mi++) {
45 | for (int ui = 0; ui < users.size(); ui++) {
46 | if (clubs.get(ci).members().get(mi) == users.get(ui)) {
47 | System.out.println("用户 [" + mi + "] 在俱乐部 [" + ci + "]");
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/chapter_05/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_05;
2 |
3 | /**
4 | * 重新安排换行来保持一致和紧凑
5 | *
6 | * @author biezhi
7 | * @date 2018/7/3
8 | */
9 | public class Example2 {
10 |
11 | static class Cookie {
12 | private String name;
13 | private String value;
14 | private int maxAge;
15 | private boolean isSecure;
16 |
17 | public Cookie(String name, String value, int maxAge, boolean isSecure) {
18 | this.name = name;
19 | this.value = value;
20 | this.maxAge = maxAge;
21 | this.isSecure = isSecure;
22 | }
23 | }
24 |
25 | public void part1(){
26 | Cookie c1 = new Cookie(
27 | "uid",/* key */
28 | "2018", /* value */
29 | 1800,/* expire time, seconds */
30 | false /* is safe */
31 | );
32 |
33 | Cookie c2 = new Cookie(
34 | "PICK_KEY",/* key */
35 | "ahmd13ldsws8cw", /* value */10800,/* expire time, seconds */
36 | true /* is safe */
37 | );
38 |
39 | Cookie c3 = new Cookie("REMEMBER_ME",/* key */
40 | "true", /* value */10800,/* expire time, seconds */
41 | true /* is safe */
42 | );
43 | }
44 |
45 | public void part2(){
46 | // Cookie(name, value , maxAge, isSecure)
47 | // [string | string | seconds | true/false]
48 | Cookie c1 = new Cookie("uid", "2018", 1800,false);
49 | Cookie c2 = new Cookie("PICK_KEY", "ahmd13ldsws8cw",10800,true);
50 | Cookie c3 = new Cookie("REMEMBER_ME","true",10800,true);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/chapter_04/Example5.java:
--------------------------------------------------------------------------------
1 | package chapter_04;
2 |
3 | /**
4 | * list.size
5 | *
6 | * @author biezhi
7 | * @date 2018/6/27
8 | */
9 | public class Example5 {
10 |
11 | static class List {
12 | private E[] data;
13 | private int pos;
14 |
15 | public List(E[] data) {
16 | this.data = data;
17 | }
18 |
19 | int countSize() {
20 | int size = 0;
21 | for (E e: data) {
22 | if (null != e) {
23 | size += 1;
24 | }
25 | }
26 | return size;
27 | }
28 |
29 | int size() {
30 | return data.length - pos;
31 | }
32 |
33 | E popBack() {
34 | pos++;
35 | E lastItem = data[data.length - pos];
36 | data[data.length - pos] = null;
37 | return lastItem;
38 | }
39 |
40 | }
41 |
42 | private void shrinkList(List list, int maxSize) {
43 | while (list.size() > maxSize) {
44 | freeNode(list.popBack());
45 | }
46 | }
47 |
48 | private void freeNode(String item) {
49 | System.out.println("释放了: " + item);
50 | }
51 |
52 | public static void main(String[] args) {
53 | String[] items = new String[10_0000];
54 |
55 | for (int i = 0; i < items.length; i++) {
56 | items[i] = "hello_#" + i;
57 | }
58 |
59 | List list = new List<>(items);
60 | Example5 example5 = new Example5();
61 | long startMs = System.currentTimeMillis();
62 | example5.shrinkList(list, 10);
63 | System.out.println((System.currentTimeMillis() - startMs) + "ms");
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/chapter_08/Example5.java:
--------------------------------------------------------------------------------
1 | package chapter_08;
2 |
3 | /**
4 | * 在方法/函数中提前返回
5 | * 最小化嵌套
6 | *
7 | * @author biezhi
8 | * @date 2018/7/11
9 | */
10 | public class Example5 {
11 |
12 | public boolean contains(String str, String subString) {
13 | if (str == null || subString == null) {
14 | return false;
15 | }
16 | if (subString.equals("")) {
17 | return true;
18 | }
19 | return str.indexOf(subString) != -1;
20 | }
21 |
22 | final int SUCCESS = 200;
23 |
24 | // public void part1() {
25 | // int userResult = 200;
26 | // int permissionResult = 300;
27 | //
28 | // String message = "";
29 | // if (userResult == SUCCESS) {
30 | // if (permissionResult != SUCCESS) {
31 | // message = "没有权限阅读";
32 | // return;
33 | // }
34 | // message = "";
35 | // } else {
36 | // message = String.valueOf(userResult);
37 | // }
38 | // // 模拟使用 message
39 | // System.out.println(message);
40 | // }
41 |
42 | public void part2() {
43 | int userResult = 200;
44 | int permissionResult = 300;
45 |
46 | String message = "";
47 | if(userResult != SUCCESS){
48 | message = String.valueOf(userResult);
49 | // 模拟使用 message
50 | System.out.println(message);
51 | return;
52 | }
53 | if (permissionResult != SUCCESS) {
54 | message = "没有权限阅读";
55 | // 模拟使用 message
56 | System.out.println(message);
57 | return;
58 | }
59 | message = "";
60 | // 模拟使用 message
61 | System.out.println(message);
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/chapter_10/Example5.java:
--------------------------------------------------------------------------------
1 | package chapter_10;
2 |
3 | import java.time.LocalDateTime;
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | /**
10 | * 把定义向下移
11 | *
12 | * @author biezhi
13 | * @date 2018/7/25
14 | */
15 | public class Example5 {
16 |
17 | private static final int MAX_SPAM_VOTES = 10;
18 |
19 | private Map messages = new HashMap<>();
20 | private Map> replies = new HashMap<>();
21 |
22 | class Message {
23 | int viewCount;
24 | LocalDateTime lastViewTime;
25 |
26 | public void save() {
27 | // do save
28 | }
29 | }
30 |
31 | class Reply {
32 | int spamVotes;
33 | }
34 |
35 | // public List viewFilterdReplies(Long originalId) {
36 | // List filteredReplies = new ArrayList<>();
37 | // Message rootMessage = messages.get(originalId);
38 | // List allReplies = replies.get(originalId);
39 | //
40 | // rootMessage.viewCount += 1;
41 | // rootMessage.lastViewTime = LocalDateTime.now();
42 | // rootMessage.save();
43 | //
44 | // for (Reply reply : allReplies) {
45 | // if (reply.spamVotes > MAX_SPAM_VOTES) {
46 | // filteredReplies.add(reply);
47 | // }
48 | // }
49 | // return filteredReplies;
50 | // }
51 |
52 | public List viewFilterdReplies(Long originalId) {
53 |
54 | Message rootMessage = messages.get(originalId);
55 | rootMessage.viewCount += 1;
56 | rootMessage.lastViewTime = LocalDateTime.now();
57 | rootMessage.save();
58 |
59 | List filteredReplies = new ArrayList<>();
60 | List allReplies = replies.get(originalId);
61 | for (Reply reply : allReplies) {
62 | if (reply.spamVotes > MAX_SPAM_VOTES) {
63 | filteredReplies.add(reply);
64 | }
65 | }
66 | return filteredReplies;
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/chapter_12/Example2.java:
--------------------------------------------------------------------------------
1 | package chapter_12;
2 |
3 | /**
4 | * 从对象中抽取值
5 | *
6 | * @author biezhi
7 | * @date 2018/8/25
8 | */
9 | public class Example2 {
10 |
11 | static class Address {
12 | String countryName;
13 | String provinceName;
14 | String cityName;
15 | String areaName;
16 |
17 | public Address(String countryName, String provinceName, String cityName, String areaName) {
18 | this.countryName = countryName;
19 | this.provinceName = provinceName;
20 | this.cityName = cityName;
21 | this.areaName = areaName;
22 | }
23 | }
24 |
25 | // 上海 - 浦东
26 | // public String part1(Address address) {
27 | // String place = address.cityName;
28 | // if (place == null) {
29 | // place = address.provinceName;
30 | // }
31 | // if (place == null && "中国".equals(address.countryName)) {
32 | // place = address.countryName;
33 | // }
34 | // if (place == null) {
35 | // place = "未知城市";
36 | // }
37 | // if (address.areaName != null) {
38 | // place += " - " + address.areaName;
39 | // } else {
40 | // place += " - 无人区";
41 | // }
42 | // return place;
43 | // }
44 |
45 | // 上海 - 浦东
46 | public String part2(Address address) {
47 | String provinceName = address.provinceName;
48 | String cityName = address.cityName;
49 | String areaName = address.areaName;
50 |
51 | String firstHalf = ifNullThen("未知城市", cityName, provinceName);
52 | String secondHalf = ifNullThen("无人区", areaName);
53 | // ||
54 | return firstHalf + " - " + secondHalf;
55 | }
56 |
57 | private String ifNullThen(String defaultValue, String...args){
58 | if(null == args || args.length == 0){
59 | return defaultValue;
60 | }
61 | for (String arg : args) {
62 | if(arg != null){
63 | return arg;
64 | }
65 | }
66 | return defaultValue;
67 | }
68 |
69 | public static void main(String[] args) {
70 | Example2 example2 = new Example2();
71 | String place = example2.part2(
72 | new Address("中国", null, "上海", "徐汇区")
73 | );
74 | place = example2.part2(
75 | new Address("中国", "山西省", null, "迎泽区")
76 | );
77 | System.out.println(place);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/chapter_14/access.log.txt:
--------------------------------------------------------------------------------
1 | 2018/09/24 13:12:49 INFO [worker@threadㄧ5] c.b.s.n.HttpServerDispatcher: 200 25ms GET /static/css/style.min.css
2 | 2018/09/24 13:12:49 INFO [worker@threadㄧ6] c.b.s.n.HttpServerDispatcher: 200 23ms GET /static/plugins/jquery/3.2.1/jquery.min.js
3 | 2018/09/24 13:12:49 INFO [worker@threadㄧ4] c.b.s.n.HttpServerDispatcher: 404 25ms GET /static/plugins/vue-loading/vue-loading.min.css
4 | 2018/09/24 13:12:49 INFO [worker@threadㄧ2] c.b.s.n.HttpServerDispatcher: 200 29ms GET /static/plugins/bootstrap/3.3.7/css/bootstrap.min.css
5 | 2018/09/24 13:12:49 INFO [worker@threadㄧ3] c.b.s.n.HttpServerDispatcher: 404 27ms GET /static/plugins/limonte-sweetalert2/6.4.1/sweetalert2.min.css
6 | 2018/09/24 13:12:49 INFO [worker@threadㄧ5] c.b.s.n.HttpServerDispatcher: 200 1ms GET /static/plugins/vue/vue.min.js
7 | 2018/09/24 13:12:49 INFO [worker@threadㄧ4] c.b.s.n.HttpServerDispatcher: 200 1ms GET /static/plugins/bootstrap/3.3.7/js/bootstrap.min.js
8 | 2018/09/24 13:12:49 INFO [worker@threadㄧ1] c.b.s.n.HttpServerDispatcher: 200 29ms GET /static/plugins/jquery-steps/1.1.0/jquery.steps.css
9 | 2018/09/24 13:12:49 INFO [worker@threadㄧ3] c.b.s.n.HttpServerDispatcher: 404 1ms GET /static/plugins/limonte-sweetalert2/6.4.1/sweetalert2.min.js
10 | 2018/09/24 13:12:49 INFO [worker@threadㄧ6] c.b.s.n.HttpServerDispatcher: 200 1ms GET /static/plugins/vue-loading/vue-loading.min.js
11 | 2018/09/24 13:12:49 INFO [worker@threadㄧ1] c.b.s.n.HttpServerDispatcher: 200 1ms GET /static/plugins/axios/axios.min.js
12 | 2018/09/24 13:12:49 INFO [worker@threadㄧ2] c.b.s.n.HttpServerDispatcher: 200 3ms GET /static/plugins/jquery-validate/1.15.1/jquery.validate.min.js
13 | 2018/09/24 13:12:49 INFO [worker@threadㄧ4] c.b.s.n.HttpServerDispatcher: 200 2ms GET /static/plugins/jquery-validate/1.15.1/localization/messages_zh.min.js
14 | 2018/09/24 13:12:49 INFO [worker@threadㄧ5] c.b.s.n.HttpServerDispatcher: 200 1ms GET /static/js/base.js
15 | 2018/09/24 13:12:49 INFO [worker@threadㄧ4] c.b.s.n.HttpServerDispatcher: 404 25ms GET /static/plugins/vue-loading/vue-loading.min.css
16 | 2018/09/24 13:12:49 INFO [worker@threadㄧ6] c.b.s.n.HttpServerDispatcher: 200 1ms GET /static/plugins/jquery-steps/1.1.0/jquery.steps.min.js
17 | 2018/09/24 13:12:49 INFO [worker@threadㄧ3] c.b.s.n.HttpServerDispatcher: 200 1ms GET /static/js/install.js
18 | 2018/09/24 13:12:49 INFO [worker@threadㄧ1] c.b.s.n.HttpServerDispatcher: 200 2ms GET /robots.txt
19 | 2018/09/24 13:12:49 INFO [worker@threadㄧ1] c.b.s.n.HttpServerDispatcher: 200 2ms GET /static/images/bg/5.png
20 | 2018/09/24 13:12:50 INFO [worker@threadㄧ1] c.b.s.n.HttpServerDispatcher: 500 2ms GET /index
--------------------------------------------------------------------------------
/src/main/java/chapter_05/Example5.java:
--------------------------------------------------------------------------------
1 | package chapter_05;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.Set;
7 | import java.util.stream.Collectors;
8 |
9 | /**
10 | * 把代码分成段落
11 | *
12 | * @author biezhi
13 | * @date 2018/7/3
14 | */
15 | public class Example5 {
16 |
17 | private String findGameAccount(String username){
18 | return null;
19 | }
20 |
21 | private String findAccountArea(String account){
22 | return null;
23 | }
24 |
25 | public List part1(List users){
26 | List accounts = users.stream().map(this::findGameAccount).collect(Collectors.toList());
27 | Map accountArea = accounts.stream().collect(Collectors.toMap((account) -> account, this::findAccountArea));
28 | Set> entries = accountArea.entrySet();
29 | List successUsers = new ArrayList<>();
30 | // for (Map.Entry entry: entries) {
31 | // try {
32 | // System.out.println("给 ["+ entry.getKey() +"] ["+ entry.getValue() +"] 发送游戏道具");
33 | // System.out.println("给 ["+ entry.getKey() +"] 发送邮件通知");
34 | // successUsers.add(entry.getKey());
35 | // } catch (Exception e){
36 | // e.printStackTrace();
37 | // }
38 | // }
39 | System.out.println("2018-07-03 发送了["+ successUsers.size() +"]个 xxx 游戏道具");
40 | return successUsers;
41 | }
42 |
43 | public List part2(List users){
44 | // 查找游戏账号和大区
45 | List accounts = users.stream().map(this::findGameAccount).collect(Collectors.toList());
46 | Map accountArea = accounts.stream()
47 | .collect(Collectors.toMap((account) -> account, this::findAccountArea));
48 |
49 | // 给账号发送道具,并发送邮件通知
50 | List successUsers = accountArea.entrySet().stream()
51 | .map(this::sendGameProp).collect(Collectors.toList());
52 |
53 | // 记录日志
54 | System.out.println("2018-07-03 发送了["+ successUsers.size() +"]个 xxx 游戏道具");
55 | return successUsers;
56 | }
57 |
58 | private String sendGameProp(Map.Entry accountEntry){
59 | try {
60 | System.out.println("给 ["+ accountEntry.getKey() +"] ["+ accountEntry.getValue() +"] 发送游戏道具");
61 | System.out.println("给 ["+ accountEntry.getKey() +"] 发送邮件通知");
62 | return accountEntry.getKey();
63 | } catch (Exception e){
64 | throw new RuntimeException(e);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/chapter_13/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_13;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * 用自然语言描述解决方案
8 | *
9 | * @author biezhi
10 | * @date 2018/9/1
11 | */
12 | public class Example3 {
13 |
14 | class Movie {
15 | Integer id;
16 | String title;
17 | String coverImage;
18 | String intro;
19 | }
20 |
21 | class CurrentIndex {
22 | int title = 0;
23 | int cover = 0;
24 | int intro = 0;
25 | }
26 |
27 | private List findAll(String sql) {
28 | return new ArrayList<>();
29 | }
30 |
31 | public void printMoive() {
32 | List titles = findAll("SELECT id, title FROM movie1 ORDER BY id ASC");
33 | List coverImages = findAll("SELECT id, cover_image FROM movie2 ORDER BY id ASC");
34 | List intros = findAll("SELECT id, intro FROM movie3 ORDER BY id ASC");
35 |
36 | CurrentIndex currentIndex = new CurrentIndex();
37 |
38 | for (Movie movie : titles) {
39 |
40 | boolean matched = advanceToMatchIndex(currentIndex, titles, coverImages, intros);
41 | if(!matched){
42 | break;
43 | }
44 | System.out.print("id: " + titles.get(currentIndex.title).id);
45 | System.out.print(", title: " + titles.get(currentIndex.title).title);
46 | System.out.print(", cover: " + coverImages.get(currentIndex.cover).coverImage);
47 | System.out.print(", intro: " + intros.get(currentIndex.intro).intro);
48 | System.out.print("\n");
49 |
50 | currentIndex.title++;
51 | currentIndex.cover++;
52 | currentIndex.intro++;
53 | }
54 |
55 | }
56 |
57 | private boolean advanceToMatchIndex(CurrentIndex currentIndex,
58 | List titles,
59 | List coverImages,
60 | List intros){
61 |
62 | for (Movie title : titles) {
63 | int titleId = titles.get(currentIndex.title).id;
64 | int coverId = coverImages.get(currentIndex.cover).id;
65 | int introId = intros.get(currentIndex.intro).id;
66 |
67 | if(titleId == coverId && titleId == introId){
68 | return true;
69 | }
70 |
71 | int maxId = getMaxId(titleId, coverId, introId);
72 | if(titleId < maxId){
73 | currentIndex.title++;
74 | }
75 | if(coverId < maxId){
76 | currentIndex.cover++;
77 | }
78 | if(introId < maxId){
79 | currentIndex.intro++;
80 | }
81 | }
82 |
83 | return false;
84 | }
85 |
86 | private Integer getMaxId(Integer...ids){
87 | return ids[0] > ids[1] ?
88 | Math.max(ids[0], ids[2]) : Math.max(ids[1], ids[2]);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Java template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.nar
19 | *.ear
20 | *.zip
21 | *.tar.gz
22 | *.rar
23 |
24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
25 | hs_err_pid*
26 | ### JetBrains template
27 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
28 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
29 |
30 | # User-specific stuff
31 | .idea/**/workspace.xml
32 | .idea/**/tasks.xml
33 | .idea/**/dictionaries
34 | .idea/**/shelf
35 |
36 | # Sensitive or high-churn files
37 | .idea/**/dataSources/
38 | .idea/**/dataSources.ids
39 | .idea/**/dataSources.local.xml
40 | .idea/**/sqlDataSources.xml
41 | .idea/**/dynamic.xml
42 | .idea/**/uiDesigner.xml
43 | .idea/**/dbnavigator.xml
44 |
45 | # Gradle
46 | .idea/**/gradle.xml
47 | .idea/**/libraries
48 |
49 | # CMake
50 | cmake-build-debug/
51 | cmake-build-release/
52 |
53 | # Mongo Explorer plugin
54 | .idea/**/mongoSettings.xml
55 |
56 | # File-based project format
57 | *.iws
58 |
59 | # IntelliJ
60 | out/
61 |
62 | # mpeltonen/sbt-idea plugin
63 | .idea_modules/
64 |
65 | # JIRA plugin
66 | atlassian-ide-plugin.xml
67 |
68 | # Cursive Clojure plugin
69 | .idea/replstate.xml
70 |
71 | # Crashlytics plugin (for Android Studio and IntelliJ)
72 | com_crashlytics_export_strings.xml
73 | crashlytics.properties
74 | crashlytics-build.properties
75 | fabric.properties
76 |
77 | # Editor-based Rest Client
78 | .idea/httpRequests
79 | ### Maven template
80 | target/
81 | pom.xml.tag
82 | pom.xml.releaseBackup
83 | pom.xml.versionsBackup
84 | pom.xml.next
85 | release.properties
86 | dependency-reduced-pom.xml
87 | buildNumber.properties
88 | .mvn/timing.properties
89 |
90 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
91 | !/.mvn/wrapper/maven-wrapper.jar
92 | ### Eclipse template
93 |
94 | .metadata
95 | bin/
96 | tmp/
97 | *.tmp
98 | *.bak
99 | *.swp
100 | *~.nib
101 | local.properties
102 | .settings/
103 | .loadpath
104 | .recommenders
105 |
106 | # External tool builders
107 | .externalToolBuilders/
108 |
109 | # Locally stored "Eclipse launch configurations"
110 | *.launch
111 |
112 | # PyDev specific (Python IDE for Eclipse)
113 | *.pydevproject
114 |
115 | # CDT-specific (C/C++ Development Tooling)
116 | .cproject
117 |
118 | # CDT- autotools
119 | .autotools
120 |
121 | # Java annotation processor (APT)
122 | .factorypath
123 |
124 | # PDT-specific (PHP Development Tools)
125 | .buildpath
126 |
127 | # sbteclipse plugin
128 | .target
129 |
130 | # Tern plugin
131 | .tern-project
132 |
133 | # TeXlipse plugin
134 | .texlipse
135 |
136 | # STS (Spring Tool Suite)
137 | .springBeans
138 |
139 | # Code Recommenders
140 | .recommenders/
141 |
142 | # Scala IDE specific (Scala & Java development for Eclipse)
143 | .cache-main
144 | .scala_dependencies
145 | .worksheet
146 | ### VisualStudioCode template
147 | .vscode/*
148 | !.vscode/settings.json
149 | !.vscode/tasks.json
150 | !.vscode/launch.json
151 | !.vscode/extensions.json
152 |
153 | .idea/
154 | *.iml
--------------------------------------------------------------------------------
/src/main/java/chapter_12/Example3.java:
--------------------------------------------------------------------------------
1 | package chapter_12;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | /**
7 | * 大一点的例子
8 | *
9 | * @author biezhi
10 | * @date 2018/8/25
11 | */
12 | public class Example3 {
13 |
14 | private Map> counts = new HashMap<>();
15 |
16 | class EventLog {
17 | String exitState;
18 |
19 | boolean hasExitState() {
20 | return exitState != null;
21 | }
22 |
23 | }
24 |
25 | class HttpHeaders {
26 | int code;
27 | String contentType;
28 |
29 | boolean hasResponseCode() {
30 | return true;
31 | }
32 |
33 | boolean hasContentType() {
34 | return true;
35 | }
36 | }
37 |
38 | class HttpDownload {
39 | EventLog eventLog;
40 | HttpHeaders httpHeaders;
41 |
42 | boolean hasEventLog() {
43 | return eventLog != null;
44 | }
45 |
46 | boolean hasHttpHeaders() {
47 | return httpHeaders != null;
48 | }
49 | }
50 |
51 | void updateCounts1(HttpDownload hd) {
52 | // counts["exitState"][hd.exitState()]++; "SUCCESS" | "FAILURE"
53 | // counts["httpStatus"][hd.statusCode()]++; "404" | "200"
54 | // counts["contentType"][hd.contentType()]++; "text/html" | "application/json"
55 | }
56 |
57 | // void updateCounts2(HttpDownload hd) {
58 | // if (!hd.hasEventLog() || !hd.eventLog.hasExitState()) {
59 | // int plus = 0; // 计算当前值+1
60 | // counts.get("exitState").putIfAbsent("unknown", plus);
61 | // } else {
62 | // int plus = 0;
63 | // String state = hd.eventLog.exitState;
64 | // counts.get("exitState").putIfAbsent(state, plus);
65 | // }
66 | //
67 | // if (!hd.hasHttpHeaders()) {
68 | // int plus = 0;
69 | // counts.get("httpStatus").putIfAbsent("unknown", plus);
70 | // counts.get("contentType").putIfAbsent("unknown", plus);
71 | // return;
72 | // }
73 | //
74 | // HttpHeaders httpHeaders = hd.httpHeaders;
75 | //
76 | // // 记录 httpStatus 的计数,不存在则记录为 unknown
77 | // if (!httpHeaders.hasResponseCode()) {
78 | // int plus = 0; // 计算当前值+1
79 | // counts.get("httpStatus").putIfAbsent("unknown", plus);
80 | // } else {
81 | // int plus = 0;
82 | // String code = String.valueOf(httpHeaders.code);
83 | // counts.get("httpStatus").putIfAbsent(code, plus);
84 | // }
85 | //
86 | // // 记录 contentType 的计数,不存在则记录为 unknown
87 | // if (!httpHeaders.hasContentType()) {
88 | // int plus = 0;
89 | // counts.get("contentType").putIfAbsent("unknown", plus);
90 | // } else {
91 | // int plus = 0;
92 | // String contentType = httpHeaders.contentType;
93 | // counts.get("contentType").putIfAbsent(contentType, plus);
94 | // }
95 | // }
96 |
97 | void updateCounts3(HttpDownload hd) {
98 | String exitState = "unknown";
99 | String httpStatus = "unknown";
100 | String contentType = "unknown";
101 |
102 | if (hd.hasEventLog() && hd.eventLog.hasExitState()) {
103 | exitState = hd.eventLog.exitState;
104 | }
105 |
106 | if(hd.hasHttpHeaders() && hd.httpHeaders.hasResponseCode()){
107 | httpStatus = String.valueOf(hd.httpHeaders.code);
108 | }
109 |
110 | if(hd.hasHttpHeaders() && hd.httpHeaders.hasContentType()){
111 | contentType = hd.httpHeaders.contentType;
112 | }
113 |
114 | int plus = 0; // 计算当前值+1
115 | counts.get("exitState").putIfAbsent(exitState, plus);
116 | counts.get("httpStatus").putIfAbsent(httpStatus, plus);
117 | counts.get("contentType").putIfAbsent(contentType, plus);
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------