一、前言
在我印象中,《Java开发手册》是一本描述Java技术细节规范的文档,这本《码出高效——Java开发手册》确乎开了眼界。介绍的内容可不仅仅只是“代码风格”。
正如书中简介一样:本书以打造民族标杆图书为己任。我看了后,感触很多。
二、一起回顾
说说我学到的新东西:
-
原码、反码、补码这里介绍得比类似《计算机操作系统》、《计算机编译原理》要好;
-
TCP的3次握手,4次”分手“,讲得好极了!wiresshark工具可以抓包,相比Charles,这是很高级的网络封包抓取工具,不妨试一试?
-
fd不足(File Descriptor),就导致无法建立更多的TCP连接。这个我遇到过2次,网上搜答案处理的,不过那时候仅仅只是处理而已,解决了问题却不知道这个涉及的就是TCP的知识;
-
SQL注入有了更直观的理解,以前总是理解的含含糊糊;
-
XSS、CSRF攻击。生产环境都会发OPTIONS请求,获取Token之后,方可安全访问;测试和开发一般没怎么关注这个,这输入RESE模块的架构;
-
几个原则
- 里氏替换原则-LSP(Liskov Substitution Principle)(对继承而言的,解决什么时候该使用继承的问题)
- 迪米特法则 —— 针对封装而言。外部只关注行为本身,二不关注实现细节;
- DRY——Don’t Repeat Yourself! 不要出现重复代码
- AIR —— Automatic(自动化)、 Independent(独立性)、Repeatable(可重复)
- BCDE —— B Border:边界测试;C Correct 正确的输入,预期的结果;D Design ,依据设计文档写单测;E Error,发现问题
-
2种编程理念
- 防御式编程。感觉类似”悲观锁“中的悲观的意思。就是对参数理性上不要做任何信任,要全部校验,尤其是边界值;你认为前端不会这么传,万一前端编码错误,就这么传了呢?不就报错了嘛?有一期的功能:健康档案板块,用户需要填写”吸烟史“相关信息:每月抽___根烟。这里是用户自己输入的,有一天用户输入1.3根,就报错了。用户解释得很有道理:我一年就吃一包多烟,平均下来不就是1.3根嘛?。。。对于用户输入的地方,一定要做校验,不可有侥幸心理。怎么处理呢?这个属性定义的是:private Integer smokePerDay;用ObjectMapper直接把JSON吸烟史前端传入的的JSON串转成对象,用try{} catch(){}捕获然后throw BussinessException(”“);即可。
- 契约式编程。 我俩协商好,都遵守这个啊。问题是,一旦一方”不遵守“了怎么办?
-
泛型类型擦除这块还是有点懵;
-
JVM的字节码,知道这个,有时候看代码可以看看字节码的处理流程,书中也有不少类似的查看方式,可以用命令行看(javap -verbose -p),也可以用jclasslib bytecode插件查看;
eg: 随便找一个BinarySearch.java,看一下字节码
// 生成BinarySearch.class
javac BinarySearch.java
// 查看字节码
javap -c BinarySearch.class
// 结果如下
public static int rank(int, int[]);
Code:
0: aload_1
1: iload_0
2: invokestatic #2 // Method indexOf:([II)I
5: ireturn
public static void main(java.lang.String[]);
Code:
0: new #3 // class edu/princeton/cs/algs4/In
3: dup
4: aload_0
5: iconst_0
6: aaload
7: invokespecial #4 // Method edu/princeton/cs/algs4/In."<init>":(Ljava/lang/String;)V
10: astore_1
11: aload_1
12: invokevirtual #5 // Method edu/princeton/cs/algs4/In.readAllInts:()[I
15: astore_2
16: aload_2
17: invokestatic #6 // Method java/util/Arrays.sort:([I)V
20: invokestatic #7 // Method edu/princeton/cs/algs4/StdIn.isEmpty:()Z
23: ifne 46
26: invokestatic #8 // Method edu/princeton/cs/algs4/StdIn.readInt:()I
29: istore_3
30: aload_2
31: iload_3
32: invokestatic #2 // Method indexOf:([II)I
35: iconst_m1
36: if_icmpne 43
39: iload_3
40: invokestatic #9 // Method edu/princeton/cs/algs4/StdOut.println:(I)V
43: goto 20
46: return
随便看看,就会遇到几个熟悉的操作码助记符:new dub invokespecial invokestatic invokevirtual return 等......
-
内存的布局 ,对内存的”模样“有了深刻的体会 公司的缓存怎么实现的?用Redis? 有些简单场景,直接就用Map做简单的缓存,缓存到内存中即可。
-
GC算法:标记-清除算法;标记-整理算法;常见垃圾回收器:Serial CMS GI
-
异常的级别。日志框架一般用slf4j+logstash 笔者每次使用Log框架,都是输出info级别的日志;debug级别的都没用过;以后这方面要更加灵活些,不同场景用不同级别的日志,而且记录日志要动脑子: 日志是否有人看?看到后能做什么?能不能提升问题排查效率?
-
集合世界的fail-fast机制、fail-safe机制;java.util下的所有集合类都是fail-fast的,而concurrent包中的结合都是fail-safe的。最常见的例子是遍历集合,然后CUD数据,会立马报错:ConcurrentModificationException
-
树 缺少树运用实战经验…
-
HashMap ConcurrentHashMap看得是云里雾里…
-
并发(Concurrency)与并行(Parallelism)、线程同步(感觉类似资源调度)
-
线程同步有几个概念:volatile (没用过);信号量同步,作者举例非常实用;
-
线程池的好处
-
ThreadLocal 我们公司怎么用的呢?我们每个Resources(接口层),都会extends一个AbstractResources,这个AbstractResources可以获取当前用户、当前登录机构、当前角色等信息,这些”当前“的信息,背后就是ThreadLocal实现的;
-
单元测试 笔者也买过不少测试方面的书籍,没遇到一本介绍单元测试有这本精彩的!如何算单测覆盖率?(粗粒度、细粒度(Line Coverage ;Branch Coverage ; Condition Decision Coverage; Multiple Condition Coverage; Path Coverage))其实,无论怎么覆盖,核心点都是要有合适测试用例,测试用例要有合适的路径,不能想当然、简单的测,要用心设计”测试用例“,这不仅只是测试的事。
-
单元测试框架:JUnit 、TestNG ;断言工具:AssertJ
-
一些源码解析:万万没想到,这本书里面有不少篇幅是介绍源码的,算是开眼界了。笔者原本以为这本书单纯讲解编码规范的,源码讲得很好,一步一步,都有注释,棒极了!
-
文章中,作者不少地方举例都是信手拈来,而且都是很贴切、很实用的场景,有拨云见日之感
三、总结
书中自有黄金屋啊。感觉自己”美丽“了许多。