diff --git a/.gitignore b/.gitignore index 0747bc77..d937c33d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,5 @@ .classpath *.log target/ -vjkit/bin -vjkit/docs -vjkit/CHANGELOG.md -vjmap/bin -vjtop/bin standard/docs/ali1.3.1.pdf -vip-book.md +standard/docs/vip-book.md diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..d240b9cc --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2006-2012] [www.springside.org.cn] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 328930f1..2f3fae13 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,30 @@ -# vjtools -唯品会JDK 问题排查及性能调优工具 +# VJTools + +主力于Java的唯品会,关于Java的一些小家底。 [![Build Status](https://travis-ci.org/vipshop/vjtools.svg?branch=master)](https://travis-ci.org/vipshop/vjtools) + + +# Java开发手册 + +| 项目 | 描述 | +| -------- | -------- | +| [standard](/standard) | 唯品会Java开发手册| +| [code formatter](/standard/formatter) | 格式化模板 | + + +# 核心类库 + +| 项目 | 描述 | +| -------- | -------- | +| [vjkit](/vjkit) | 关于文本,集合,并发,反射等基础功能的核心类库 | + + +# Java工具集 + + +| 项目 | 描述 | +| -------- | -------- | +| [vjmap](/vjmap) | 打印堆内各分代中对象的统计信息 | +| [vjtop](/vjtop) | 打印JVM概况及繁忙的java线程 | + + +其他推荐的三方问题排查及性能调优工具包括:btrace,greys,async-profiler diff --git a/standard/docs/chapter01.md b/standard/docs/chapter01.md index d1d5a929..d945d981 100644 --- a/standard/docs/chapter01.md +++ b/standard/docs/chapter01.md @@ -89,16 +89,16 @@ private static Logger logger = Logger.getLogger(MyClass.class); 1)如果上下文很清晰,局部变量可以使用 `list` 这种简略命名, 否则应该使用 `userList` 这种更清晰的命名。 -
+ 2)禁止 `a1, a2, a3` 这种带编号的没诚意的命名方式。 -
+ 3)方法的参数名叫 `bookList` ,方法里的局部变量名叫 `theBookList` 也是很没诚意。 -
+ 4)如果一个应用里同时存在 `Account、AccountInfo、AccountData` 类,或者一个类里同时有 `getAccountInfo()、getAccountData()`, `save()、 store()` 的函数,阅读者将非常困惑。 -
+ 5) `callerId` 与 `calleeId`, `mydearfriendswithA` 与 `mydearfriendswithB` 这种拼写极度接近,考验阅读者眼力的。 ---- @@ -168,4 +168,4 @@ public class B extends A { ---- -* [下一章:格式规约](chapter02.md) \ No newline at end of file +* [下一章:格式规约](chapter02.md) diff --git a/standard/docs/chapter02.md b/standard/docs/chapter02.md index e6f39557..f546555c 100644 --- a/standard/docs/chapter02.md +++ b/standard/docs/chapter02.md @@ -4,16 +4,16 @@ 1)IDE的默认代码格式模板,能简化绝大部分关于格式规范(如空格,括号)的描述。 -
+ 2)统一的模板避免不同开发者之间,因为格式不统一,产生代码合并冲突。另外,代码变更日志中因为格式不同引起的变更,也会掩盖了真正的逻辑变更。 -
+ 3)设定项目组统一的行宽,建议120。 -
+ 4)设定项目组统一的缩进方式(Tab或二空格,四空格均可),基于IDE自动转换。 -
+ * [VIP标准代码格式化模板](/standard/formatter) ---- @@ -40,7 +40,7 @@ if ((a == b) && (c == d)) 按方法的对阅读者的关心程度排列,如果公有方法可以分成几组,私有方法也可以紧跟公有方法分组。 -
+ 2)当一个类有多个构造方法,或者多个同名的重载方法,这些方法应该按顺序放置在一起。其中参数较多的方法在后面。 ```java @@ -51,7 +51,7 @@ public void foo(int a) {...} public void foo(int a, String b) {...} ``` -
+ 3)作为调用者的方法,尽量放在被调用的方法前面。 ```java diff --git a/standard/docs/chapter04.md b/standard/docs/chapter04.md index 63799ffe..396d4763 100644 --- a/standard/docs/chapter04.md +++ b/standard/docs/chapter04.md @@ -48,12 +48,12 @@ try { 例外: 你不希望依赖整个对象,传播了类之间的依赖性。 -
+ 2)将多个参数合并为一个新创建的逻辑对象。 例外: 多个参数之间毫无逻辑关联。 -
+ 3)将函数拆分成多个函数,让每个函数所需的参数减少。 * [Sonar-107: Methods should not have too many parameters](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-107) @@ -85,12 +85,12 @@ Validate.isTrue(length > 2, "length is %d, less than 2", length); 1) 极有可能被循环调用的方法。 -
+ 2) 底层调用频度比较高的方法。毕竟是像纯净水过滤的最后一道,参数错误不太可能到底层才会暴露问题。 比如,一般DAO层与Service层都在同一个应用中,所以DAO层的参数校验,可以省略。 -
+ 3) 被声明成private,或其他只会被自己代码所调用的方法,如果能够确定在调用方已经做过检查,或者肯定不会有问题则可省略。 即使忽略检查,也尽量在方法说明里注明参数的要求,比如vjkit中的@NotNull,@Nullable标识。 @@ -162,4 +162,4 @@ a.hello(arrayList); ---- * [上一章:注释规约](chapter03.md) -* [下一章:类设计](chapter05.md) \ No newline at end of file +* [下一章:类设计](chapter05.md) diff --git a/standard/docs/chapter05.md b/standard/docs/chapter05.md index 2557797c..a4d656d6 100644 --- a/standard/docs/chapter05.md +++ b/standard/docs/chapter05.md @@ -108,7 +108,7 @@ int i = ClassA.staticMethod(); // RIGHT * [Sonar-2209: "static" members should be accessed statically](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-2209) * [Sonar-2440: Classes with only "static" methods should not be instantiated](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-2440) -
+ **9.2 【推荐】除测试用例,不要static import 静态方法** 静态导入后忽略掉的类名,给阅读者造成障碍。 @@ -117,7 +117,7 @@ int i = ClassA.staticMethod(); // RIGHT * [Sonar-3030: Classes should not have too many "static" imports](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-3030) 但IDEA经常自动转换static import,所以暂不作为规则。 -
+ **9.3【推荐】尽量避免在非静态方法中修改静态成员变量的值** ```java @@ -145,7 +145,7 @@ public void foo() { 在性能上没有区别;当内部类会被多个地方调用,或匿名内部类的长度太长,已影响对调用它的方法的阅读时,定义有名字的内部类。 -
+ 2) 静态内部类 与 内部类,优先使用静态内部类: 1. 非静态内部类持有外部类的引用,能访问外类的实例方法与属性。构造时多传入一个引用对性能没有太大影响,更关键的是向阅读者传递自己的意图,内部类会否访问外部类。 @@ -172,7 +172,7 @@ public void foo() { 但getter/seter中不应有复杂的业务处理,建议另外封装函数,并且不要以getXX/setXX命名。 -
+ 如果是内部类,以及无逻辑的POJO/VO类,使用getter/setter除了让一些纯OO论者感觉舒服,没有任何的好处,建议直接使用public成员变量。 例外:有些序列化框架只能从getter/setter反射,不能直接反射public成员变量。 @@ -187,19 +187,19 @@ public void foo() { **Rule 13. hashCode和equals方法的处理,遵循如下规则:** -
+ **13.1【强制】只要重写equals,就必须重写hashCode。 而且选取相同的属性进行运算。** -
+ **13.2【推荐】只选取真正能决定对象是否一致的属性,而不是所有属性,可以改善性能。** -
+ **13.3【推荐】对不可变对象,可以缓存hashCode值改善性能(比如String就是例子)。** -
+ **13.4【强制】类的属性增加时,及时重新生成toString,hashCode和equals方法。** -
+ * [Sonar-1206: "equals(Object obj)" and "hashCode()" should be overridden in pairs](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-1206) ---- @@ -260,4 +260,4 @@ obj.getA().getB().getC().hello(); ---- * [上一章:方法设计](chapter04.md) -* [下一章:控制语句](chapter06.md) \ No newline at end of file +* [下一章:控制语句](chapter06.md) diff --git a/standard/docs/chapter06.md b/standard/docs/chapter06.md index e762e2b5..8773c9b0 100644 --- a/standard/docs/chapter06.md +++ b/standard/docs/chapter06.md @@ -162,4 +162,4 @@ do-while语句要在循环最后才看到循环条件,不利于代码维护, ---- * [上一章:类设计](chapter05.md) -* [下一章:基本类型](chapter07.md) \ No newline at end of file +* [下一章:基本类型](chapter07.md) diff --git a/standard/docs/chapter07.md b/standard/docs/chapter07.md index dea31fde..4a0148e9 100644 --- a/standard/docs/chapter07.md +++ b/standard/docs/chapter07.md @@ -4,13 +4,13 @@ **1.1 【推荐】需要序列化的POJO类属性使用包装数据类型** -
+ **1.2 【推荐】RPC方法的返回值和参数使用包装数据类型** -
+ **1.3 【推荐】局部变量尽量使用基本数据类型** -
+ 包装类型的坏处: 1)Integer 24字节,而原子类型 int 4字节。 @@ -19,7 +19,7 @@ 3)包装类型还有==比较的陷阱(见规则3) -
+ 包装类型的好处: 1)包装类型能表达Null的语义。 @@ -51,7 +51,7 @@ int i = Integer.parseInt(str); * [Sonar-2153: Boxing and unboxing should not be immediately reversed](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-2153) -
+ **2.2 【推荐】自动拆箱有可能产生NPE,要注意处理** ```java @@ -67,14 +67,14 @@ int i = intObject; \==判断对象是否同一个。Integer var = ?在缓存区间的赋值(见规则1),会复用已有对象,因此这个区间内的Integer使用 \==进行判断可通过,但是区间之外的所有数据,则会在堆上新产生,不会通过。因此如果用\== 来比较数值,很可能在小的测试数据中通过,而到了生产环境才出问题。 -
+ **3.2【强制】 BigDecimal需要使用compareTo()** 因为BigDecimal的equals()还会比对精度,2.0与2.00不一致。 * Facebook-Contrib: Correctness - Method calls BigDecimal.equals() -
+ **3.3【强制】 Atomic* 系列,不能使用equals方法** 因为 Atomic* 系列没有覆写equals方法。 @@ -86,7 +86,7 @@ if (counter1.get() == counter2.get()){...} * [Sonar-2204: ".equals()" should not be used to test the values of "Atomic" classes](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-2204) -
+ **3.4【强制】 double及float的比较,要特殊处理** 因为精度问题,浮点数间的equals非常不可靠,在vjkit的NumberUtil中有对应的封装函数。 @@ -134,7 +134,7 @@ long l = Integer.MAX_VALUE * 2L; //结果是正确的4294967294 * [Sonar-2184: Math operands should be cast before assignment](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-2184) -
+ **4.2【强制】数字取模的结果不一定是正数,负数取模的结果仍然负数** 取模做数组下标时,如果不处理负数的情况,很容易ArrayIndexOutOfBoundException。 @@ -148,7 +148,7 @@ Math.abs(Integer.MIN_VALUE) = -2147483648; * Findbugs: Style - Remainder of hashCode could be negative -
+ **4.3【推荐】 double 或 float 计算时有不可避免的精度问题** ```java @@ -216,7 +216,7 @@ for (int i = 0; i < 100; i++) { * [Sonar-1643: Strings should not be concatenated using '+' in a loop](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-1643) -
+ **6.2 【强制】 字符串拼接对象时,不要显式调用对象的toString()** 如上,`+`实际是StringBuilder,本身会调用对象的toString(),且能很好的处理null的情况。 @@ -229,17 +229,17 @@ str = "result:" + myObject.toString(); // myObject为Null时,抛NPE str = "result:" + myObject; // myObject为Null时,输出 result:null ``` -
+ **6.3【强制】使用StringBuilder,而不是有所有方法都有同步修饰符的StringBuffer** 因为内联不成功,逃逸分析并不能抹除StringBuffer上的同步修饰符 * [Sonar-1149: Synchronized classes Vector, Hashtable, Stack and StringBuffer should not be used](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-1149) -
+ **6.4 【推荐】当拼接后字符串的长度远大于16时,指定StringBuilder的大概长度,避免容量不足时的成倍扩展** -
+ **6.5 【推荐】如果字符串长度很大且频繁拼接,可考虑ThreadLocal重用StringBuilder对象** 参考BigDecimal的toString()实现,及vjkit中的StringBuilderHolder。 diff --git a/standard/docs/chapter08.md b/standard/docs/chapter08.md index 484c5523..ee9f032a 100644 --- a/standard/docs/chapter08.md +++ b/standard/docs/chapter08.md @@ -6,10 +6,10 @@ 数组有大小限制,当超过容量时,需要进行复制式扩容,新申请一个是原来容量150% or 200%的数组,将原来的内容复制过去,同时浪费了内存与性能。HashMap/HashSet的扩容,还需要所有键值对重新落位,消耗更大。 -
+ 默认构造函数使用默认的数组大小,比如ArrayList默认大小为10,HashMap为16。因此建议使用ArrayList(int initialCapacity)等构造函数,明确初始化大小。 -
+ HashMap/HashSet的初始值还要考虑加载因子: 为了降低哈希冲突的概率(Key的哈希值按数组大小取模后,如果落在同一个数组下标上,将组成一条需要遍历的Entry链),默认当HashMap中的键值对达到数组大小的75%时,即会触发扩容。因此,如果预估容量是100,即需要设定`100/0.75=134`的数组大小。vjkit的MapUtil的Map创建函数封装了该计算。 @@ -107,10 +107,10 @@ keySet遍历的方式,增加了N次用key获取value的查询。 推荐使用`java.util.concurrent(JUC)`工具包中的并发版集合,如ConcurrentHashMap等,优于使用Collections.synchronizedXXX()系列函数进行同步化封装(等价于在每个方法都加上synchronized关键字)。 -
+ 例外:ArrayList所对应的CopyOnWriteArrayList,每次更新时都会复制整个数组,只适合于读多写很少的场景。如果频繁写入,可能退化为使用Collections.synchronizedList(list)。 -
+ 2) 即使线程安全类仍然要注意函数的正确使用。 例如:即使用了ConcurrentHashMap,但直接是用get/put方法,仍然可能会多线程间互相覆盖。 @@ -156,7 +156,7 @@ Iterable integers = ...; stack.pushAll(integers); ``` -
+ 2) 如果集合要被写入,定义成`` ```java diff --git a/standard/docs/chapter09.md b/standard/docs/chapter09.md index cd687059..8b659d32 100644 --- a/standard/docs/chapter09.md +++ b/standard/docs/chapter09.md @@ -44,12 +44,12 @@ Executors返回的线程池对象的弊端 : 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 -
+ 2)CachedThreadPool 和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。 -
+ 应通过 new ThreadPoolExecutor(xxx,xxx,xxx,xxx)这样的方式,更加明确线程池的运行规则,合理设置Queue及线程池的core size和max size,建议使用vjkit封装的ThreadPoolBuilder。 ---- @@ -95,7 +95,7 @@ public void run() { } ``` -
+ **5.1 正确处理InterruptException** 因为InterruptException异常是个必须处理的Checked Exception,所以run()所调用的子函数很容易吃掉异常并简单的处理成打印日志,但这等于停止了中断的传递,外层函数将收不到中断请求,继续原有循环或进入下一个堵塞。 @@ -115,7 +115,7 @@ public void myMethod() { * [Sonar-2142: "InterruptedException" should not be ignored](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-2142) -
+ **5.2 主循环及进入阻塞状态前要判断线程状态** @@ -146,7 +146,7 @@ public void run() { 3) 如果没有在ThreadFactory设置自定义的UncaughtExceptionHanlder,则异常最终只打印在System.err,而不会打印在项目的日志中。 -
+ 因此建议自写的Runnable都要保证捕获异常; 如果是第三方的Runnable,可以将其再包裹一层vjkit中的SafeRunnable。 ```java @@ -233,7 +233,7 @@ synchronized(A.class) { 2) Array Base的queue一般是全局一把锁,而Linked Base的queue一般是队头队尾两把锁。 -
+ * 分散锁(又称分段锁): @@ -241,7 +241,7 @@ synchronized(A.class) { 2)对于经常写,少量读的计数器,推荐使用JDK8或vjkit封装的LongAdder对象性能更好(内部分散成多个counter,减少乐观锁的使用,取值时再相加所有counter) -
+ * 无锁的数据结构: diff --git a/standard/docs/chapter10.md b/standard/docs/chapter10.md index 217200ea..073fab53 100644 --- a/standard/docs/chapter10.md +++ b/standard/docs/chapter10.md @@ -45,7 +45,7 @@ MyClass.class, "mymethod"); throw TIMEOUT_EXCEPTION; ``` -
+ 2) 如果异常的message会变化,则对静态的异常实例进行clone()再修改message。 Exception默认不是Cloneable的,`CloneableException`见vjkit。 @@ -59,7 +59,7 @@ private static CloneableException TIMEOUT_EXCEPTION = new CloneableException("Ti throw TIMEOUT_EXCEPTION.clone("Timeout for 40ms"); ``` -
+ 3)自定义异常,也可以考虑重载fillStackTrace()为空函数,但相对没那么灵活,比如无法按场景指定一层的StackTrace。 ---- @@ -100,7 +100,7 @@ logger.error("user[" + userId + "] expired:" + e.getMessage(), e); 尽量使用JDK标准的Runtime异常如`IllegalArgumentException`,`IllegalStateException`,`UnsupportedOperationException`,项目定义的Exception如`ServiceException`。 -
+ **5.2 【推荐】根据调用者的需要来定义异常类,直接使用`RuntimeException`是允许的** 是否定义独立的异常类,关键是调用者会如何处理这个异常,如果没有需要特别的处理,直接抛出RuntimeException也是允许的。 @@ -115,7 +115,7 @@ logger.error("user[" + userId + "] expired:" + e.getMessage(), e); 捕获Throwable是为了捕获Error类异常,包括其实无法处理的`OOM` `StackOverflow` `ThreadDeath`,以及类加载,反射时可能抛出的`NoSuchMethodError` `NoClassDefFoundError`等。 -
+ **6.2【推荐】多个异常的处理逻辑一致时,使用JDK7的语法避免重复代码** ```java @@ -149,7 +149,7 @@ try { } ``` -
+ **7.2 【强制】异常处理不能吞掉原异常,要么在日志打印,要么在重新抛出的异常里包含原异常** ```java @@ -166,7 +166,7 @@ throw new MyException("message", ex); * [Sonar-1166: Exception handlers should preserve the original exceptions](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-1166),其中默认包含了InterruptedException, NumberFormatException,NoSuchMethodException等若干例外 -
+ **7.3 【强制】如果不想处理异常,可以不进行捕获。但最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容** ---- @@ -185,7 +185,7 @@ try (Writer writer = ...) { } ``` -
+ **8.2 【强制】如果处理过程中有抛出异常的可能,也要做try-catch,否则finally块中抛出的异常,将代替try块中抛出的异常** ```java @@ -208,7 +208,7 @@ try { * [Sonar-1163: Exceptions should not be thrown in finally blocks](https://www.sonarsource.com/products/codeanalyzers/sonarjava/rules.html#RSPEC-1163) -
+ **8.3 【强制】不能在finally块中使用return,finally块中的return将代替try块中的return及throw Exception** ```java @@ -233,4 +233,4 @@ try { ---- * [上一章:并发处理](chapter09.md) -* [下一章:日志规约](chapter11.md) \ No newline at end of file +* [下一章:日志规约](chapter11.md) diff --git a/standard/docs/chapter11.md b/standard/docs/chapter11.md index 2fde4849..654f4f98 100644 --- a/standard/docs/chapter11.md +++ b/standard/docs/chapter11.md @@ -27,7 +27,7 @@ logger.debug("Processing trade with id: " + id + " symbol: " + symbol); logger.debug("Processing trade with id: {} symbol : {} ", id, symbol); ``` -
+ 但如果symbol.getMessage()本身是个消耗较大的动作,占位符在此时并没有帮助,须要改为条件判断方式来完全避免它的执行。 ```java diff --git a/standard/docs/chapter12.md b/standard/docs/chapter12.md index b9f48f87..14495b63 100644 --- a/standard/docs/chapter12.md +++ b/standard/docs/chapter12.md @@ -17,10 +17,10 @@ 1)获取当前毫秒数System.currentTimeMillis() 而不是new Date().getTime(),后者的消耗要大得多。 -
+ 2)如果要获得更精确的,且不受NTP时间调整影响的流逝时间,使用System.nanoTime()获得机器从启动到现在流逝的纳秒数。 -
+ 3)如果希望在测试用例中控制当前时间的值,则使用vjkit的Clock类封装,在测试和生产环境中使用不同的实现。 ---- @@ -91,4 +91,4 @@ ReflectionUtils.invoke(obj, methodName, args); ---- -* [上一章:日志规约](chapter11.md) \ No newline at end of file +* [上一章:日志规约](chapter11.md) diff --git a/standard/docs/merge.sh b/standard/docs/merge.sh index 80019a6f..6057ea09 100755 --- a/standard/docs/merge.sh +++ b/standard/docs/merge.sh @@ -28,8 +28,5 @@ cat chapter12.md >> vip-java-standard.md echo '\n' >> vip-java-standard.md cat ali.md >> vip-java-standard.md -sed -e "s|
||g" -i bak vip-java-standard.md -sed -e "s|
||g" -i bak vip-java-standard.md - echo 'upload vip-java-standard.md to http://www.mdtr2pdf.com' diff --git a/standard/formatter/README.md b/standard/formatter/README.md index 814c1ac4..d1ffae4f 100644 --- a/standard/formatter/README.md +++ b/standard/formatter/README.md @@ -4,8 +4,8 @@ 将下列profile下载并导入IDE即可,导入后Profile名称为`vipshop2.0`: -* [Eclipse Code Formatter Profile](http://gitlab.tools.vipshop.com/venus-framework/vjtools/raw/master/standard/formatter/vipshop-code-conventions.xml) -* [Intellij Code Formatter Profile](http://gitlab.tools.vipshop.com/venus-framework/vjtools/raw/master/standard/formatter/vipshop-code-conventions-idea.xml) +* [Eclipse Code Formatter Profile](https://raw.githubusercontent.com/vipshop/vjtools/master/standard/formatter/vipshop-code-conventions.xml) +* [Intellij Code Formatter Profile](https://raw.githubusercontent.com/vipshop/vjtools/master/standard/formatter/vipshop-code-conventions-idea.xml) 因为Intellij导入Eclipse Profile存在问题,因此同时提供了两者的Profile。 @@ -27,7 +27,6 @@ ## 3. 与IDEA默认模板的区别 -详见 [idea和eclipse默认模板的区别](http://wiki.corp.vipshop.com/pages/viewpage.action?pageId=424282717) 本模板参考了Intellij IDEA默认模板中如下部分: diff --git a/vjmap/README.md b/vjmap/README.md index 95e5f9d1..8df09b20 100644 --- a/vjmap/README.md +++ b/vjmap/README.md @@ -8,7 +8,7 @@ vjmap 原始思路来源于[tbjmap](https://github.com/alibaba/TBJMap) 进行了 # 2.vjmap使用 -[下载](http://mvn1.tools.vipshop.com/nexus/index.html#nexus-search;quick~vjmap), 点击zip文件的`Artifact Information` Tab,下载并解压。 +maven编译后得到zip包,解压后运行。 注意:vjmap在执行过程中,会完全停止应用,必须摘流量执行!!! diff --git a/vjtop/README.md b/vjtop/README.md index 7a9a2ee5..e95a22ae 100644 --- a/vjtop/README.md +++ b/vjtop/README.md @@ -12,7 +12,7 @@ ## 2.1 概述 -[下载包](http://mvn1.tools.vipshop.com/nexus/index.html#nexus-search;quick~vjtop), 点击zip文件的`Artifact Information` Tab,下载并解压。 +maven编译后得到zip包,解压后运行。 需要设置JAVA_HOME 环境变量,需要与所探测的JVM同一个用户,或Root用户运行