http://massivetechinterview.blogspot.com/2018/04/java-misc-part-5.html
https://sourcemaking.com/design_patterns/visitor/java/2
https://refactoring.guru/design-patterns/visitor-double-dispatch
https://lostechies.com/derekgreer/2010/04/19/double-dispatch-is-a-code-smell/
http://www.raychase.net/253
Overloading occurs when two or more methods in one class have the same method name but different parameters.
重载(Overloading)和重写(Overriding)是Java中两个比较重要的概念
https://www.xilidou.com/2018/01/22/merge-request/
https://www.xilidou.com/2017/11/28/%E6%9C%80%E8%BF%91%E9%81%87%E5%88%B0%E7%9A%84%E5%87%A0%E4%B8%AA%E5%B0%8F%E9%A2%98%E9%9B%86%E5%90%88/
When I Google “package by layer” vs. “package by feature” or “folder by type” vs. “folder by feature”, there seems to be a growing camp of proponents of the “by feature” structure. I am in this camp, too.
https://dzone.com/articles/prefer-systemlineseparator-for-writing-system-depe
https://dzone.com/articles/yet-4-more-techniques-for-writing-better-java
1. Validate Arguments With Standard Methods
https://dzone.com/articles/5-hidden-secrets-in-java
One of the limitations of enumerations (enums) compared to classes in Java is that enums cannot extend another class or enum.
We can, however, have our enum implement an interface and provide an implementation for its abstract methods
https://dzone.com/articles/java-using-immutable-classes-for-concurrent-programming
https://dzone.com/articles/3-things-every-java-developer-should-stop-doing
we have elected to return an immutable, empty list. This is an acceptable solution, so long as we document that the list is immutable and should not be modified (doing so may throw an exception).
3. Creating Indiscriminate Getters and Setters
What normally occurs in practice is that every private field is given a pair of getters and setters, exposing the internals of the class to external entities. This can cause some serious issues, especially if the private fields are mutable. This is not only a problem with setters but even when only a getter is present
It is important to note that if the fields of the class are non-primitive, a client can modify the underlying object as we saw above. Thus, immutable objects should return defensive copies of these objects, disallowing clients to modify the internal state of the immutable object. Note, though, that defensive copying can reduce performance since a new object is created each time the getter is called. This issue should not be prematurely optimized (disregarding immutability for the promise of possible performance increases), but it should be noted
http://pmd.sourceforge.net/pmd-4.3.0/rules/basic.html
@SuppressWarnings("PMD.AvoidUsingHardCodedIP")
https://stackoverflow.com/questions/10508107/why-call-super-in-a-constructor
Junit throws AssertionError.
Java would still execute finally even if the block throws Error.
https://www.quora.com/What-is-meant-by-fall-through-with-respect-to-switch-case-blocks-in-Java
The one thing I will add is that usually this type of "fallthrough" is either an accident (missing break statement) or not what was planned by the developer.
My personal preference is to avoid relying on fallthrough logic as it can create brittle code as it can be easy to disrupt the intended logic.
http://www.dummies.com/programming/java/how-to-use-fall-through-to-your-advantage-in-java-programming/
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
H Hour in day (0-23)
h Hour in am/pm (1-12)
M Month in year
m Minute in hour
y Year
Y Week year
http://www.maheshsubramaniya.com/article/understanding-how-jars-are-loaded-into-jvm-from-a-directory.html
EXT3 file system hash the filenames and places the entry in the directory level inode table.
So if your one machine load jars as
Since it is random, you cannot expect the same ordering in another machine with EXT3 file system.
So always exercise caution and do review your
记一次微服务jvm加载jar顺序机制导致的bug
The Rule: Whenever you implement logic using before/after, allocate/free, take/return semantics, think about whether the after/free/return operation should perform stuff in the inverse order.
2. Don’t trust your early SPI evolution judgement
int $ = 1;
6. Never return null arrays or lists from API methods
Implement more of a functional style. Pass state through method arguments. Manipulate less object state.
https://blog.jooq.org/2015/02/05/top-10-easy-performance-optimisations-in-java/
Optimise your hashCode() and equals() methods
A version is a tuple of 4 numbers:
Major.Minor.Bugfix.Hotfix
Major is incremented in case of big and/or non-backward compatible changes.
Minor is incremented for any change that does not require a major version bump and is a bigger change than a simple bugfix.
Bugfix is incremented to indicate a bug fixing change that is small and self-contained.
Hotfix is normally 0 and is incremented when a change is made to a previously released artifact.
https://stackoverflow.com/questions/3109950/codestyle-put-javadoc-before-or-after-annotation
https://stackoverflow.com/questions/9863742/how-to-pass-an-arraylist-to-a-varargs-method-parameter
https://dzone.com/articles/an-introduction-to-hollow-jars
If you find yourself writing a marker annotation type whose target is ElementType.TYPE, take the time to figure out whether it really should be an annotation type or whether a marker interface would be more appropriate.
http://www.java2novice.com/java-annotations/marker/
https://stackoverflow.com/questions/33170109/difference-between-optional-orelse-and-optional-orelseget
https://dzone.com/articles/java-holiday-calendar-2016-day-22-use-enums-as-met
using Enums as parameters to indicate method behavior
https://dzone.com/articles/java-holiday-calendar-2016-day-20-break-out-of-the
http://blog.csdn.net/wangyangzhizhou/article/details/79504818
https://sourcemaking.com/design_patterns/visitor/java/2
https://refactoring.guru/design-patterns/visitor-double-dispatch
https://lostechies.com/derekgreer/2010/04/19/double-dispatch-is-a-code-smell/
Polymorphic Static Binding
Polymorphic static binding is a technique where static method invocations are determined at run-time through the use of polymorphism. This can be demonstrated in our example by adding a new
Draw(Shape shape)
method to the Surface
and EtchASketch
types which call shape.Draw()
with a reference to the current object:class Surface { public virtual void Draw(Shape shape) { shape.Draw(this); } } class EtchASketch : Surface { public override void Draw(Shape shape) { shape.Draw(this); } }
To invoke the correct
Shape.Draw()
method, our console application needs to be modified to call the the method indirectly through a Surface
reference:class Program { static void Main(string[] args) { var shape = new Shape(); Surface surface = new Surface(); Surface etchASketch = new EtchASketch(); surface.Draw(shape); etchASketch.Draw(shape); Console.ReadLine(); } }
This example achieves the desired result by effectively wrapping the static-dispatched method invocation (i.e.
Shape.Draw()
) within a virtual-dispatch method invocation (i.e. Surface.Draw()
and EtchASketch.Draw()
). This causes the static Shape.Draw()
method invocation to be determined by which virtual Surface.Draw()
method invocation is executed.
So, what’s wrong with Double Dispatch? The problem isn’t so much in the technique, but what design choices might be leading to reliance upon the technique. Consider for instance the hierarchy of shape types in our Double Dispatch example. What happens if we want to add a new surface? In this case, each of the shape types will need to be modified to add knowledge of the new Surface type. This violates the Open/Closed Principle, and in this case in a particularly egregious way (i.e. It’s violation is multiplied by the number of shape types we have). Additionally, it violates the Single Responsibility Principle. Changes to how shapes are drawn on a particular surface are likely to differ from surface to surface, thereby leading our shape objects to change for different reasons.
The presence of Double Dispatch generally means that each type in a hierarchy has special handling code within another hierarchy of types. This approach to representing variant behavior leads to code that is less resilient to future changes as well as being more difficult to extend.
有一天,老板给他传达了这样一个需求,根据用户不同的图像绘制事件,画出一个圆或者是画出一个方块来。
小P想到,如果我再在代码里面增加一个if-else分支,问题是可以解决,可是分支越来越多,代码越来越丑陋,如果我可以用一个Map来代替if-else完成选择的功能,岂不是可以让我原来的实现优雅一点?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| public class Drawer { private static Map<Class, IDrawer> DRAWER_MAP = new HashMap<Class, IDrawer>(); static { DRAWER_MAP.put(RoundDrawEvent. class , new RoundDrawer()); DRAWER_MAP.put(RectangleDrawEvent. class , new RectangleDrawer()); } public void draw(DrawEvent event) { DRAWER_MAP.get(event.getClass()).draw(); } } interface IDrawer { public void draw(); } class RoundDrawer implements IDrawer { public void draw() { // 画圆 } } class RectangleDrawer implements IDrawer { public void draw() { // 画方 } } |
突然,一瞬间的火花,小P觉得如果用方法重载来代替if-else的工作,把变化的点转移到方法重载上,也可以做到:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public class Drawer { public void draw(RoundDrawEvent event) { //画圆 } public void draw(RectangleDrawEvent event) { //画方 } public void draw(DrawEvent event) { System.out.print( "error" ); } } |
可是,测试这个方法的时候,他傻眼了:
1
2
| DrawEvent event = new RoundDrawEvent(); new Drawer().draw(event); |
他发现每次输出的结果都是“error”!
而如果测试代码改成这样,却是正确的:
1
| new Drawer().draw( new RoundDrawEvent()); |
原来,在Java中,方法重载都是在编译期间确定的,对于编译期间draw方法的实参event,如果使用了DrawEvent这个接口来引用,那么结果就可想而知,去执行draw(DrawEvent event)这个方法了。
原因清楚了,接下去就不难想出解决办法:
既然方法的重载无法是动态的,那么我在调用这个重载了的方法之前,我就要给它传入一个在编译期就已经确定了具体类型的入参,把变化的点转移到对象的多态上。
可是,DrawEvent接口里并没有提供可供外部因素参与和影响的变化点,如果它能够提供一个供外部注入行为的变化点,不就可以用多态来帮助我们了么:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| interface DrawEvent { public void draw(Drawer drawer); } class RoundDrawEvent implements DrawEvent { public void draw(Drawer drawer) { drawer.draw( this ); } } class RectangleDrawEvent implements DrawEvent { public void draw(Drawer drawer) { drawer.draw( this ); } } |
这里我说明一下为什么要传入drawer参数,因为真正要画图的家伙,不是这个event,而是drawer,而这个event只不过是利用多态,起到了寻找那个合适的重载方法的作用!
好,接下去再完成Drawer就可以了:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public class Drawer { public void draw(RoundDrawEvent event) { // 画圆 } public void draw(RectangleDrawEvent event) { // 画方 } public void draw(DrawEvent event) { event.draw( this ); } } |
可以看到,其实这里的DrawEvent已经不纯粹了,不仅仅代表了事件本身,还作为一个行为的委托者,甄选具体要执行的行为,再把执行的任务交还给Drawer。
这时,我用下面的办法测试这个方法的时候,结果就是正确的了:
1
2
| DrawEvent event = new RoundDrawEvent(); new Drawer().draw(event); |
如果我把入参的引用变成具体类型,如:
1
| new Drawer().draw( new RoundDrawEvent()); |
就直接走到Drawer的draw(RoundDrawEvent event)方法上了,于是结果也是正确的。
类似的实现方式,被称为Double Dispatch,它要根据两个对象的运行时类型来选择具体的执行方法(dispatches a function call to different concrete functions depending on the runtime types of two objects involved in the call)。
https://www.programcreek.com/2009/02/overriding-and-overloading-in-java-with-examples/Overloading occurs when two or more methods in one class have the same method name but different parameters.
Overriding means having two methods with the same method name and parameters (i.e., method signature). One of the methods is in the parent class and the other is in the child class. Overriding allows a child class to provide a specific implementation of a method that is already provided its parent class.
Here are some important facts about Overriding and Overloading:
1). The real object type in the run-time, not the reference variable's type, determines which overridden method is used at runtime. In contrast, reference type determines which overloaded method will be used at compile time.
2). Polymorphism applies to overriding, not to overloading.
3). Overriding is a run-time concept while overloading is a compile-time concept.
http://www.hollischuang.com/archives/13082). Polymorphism applies to overriding, not to overloading.
3). Overriding is a run-time concept while overloading is a compile-time concept.
重载(Overloading)和重写(Overriding)是Java中两个比较重要的概念
重载(Overloading)和重写(Overriding)是Java中两个比较重要的概念。但是对于新手来说也比较容易混淆。本文通过两个简单的例子说明了他们之间的区别。
定义
重载
简单说,就是函数或者方法有同样的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。
重写
重写指的是在Java的子类与父类中有两个名称、参数列表都相同的方法的情况。由于他们具有相同的方法签名,所以子类中的新方法将覆盖父类中原有的方法。
重载 VS 重写
关于重载和重写,你应该知道以下几点:
1、重载是一个编译期概念、重写是一个运行期间概念。2、重载遵循所谓“编译期绑定”,即在编译时根据参数变量的类型判断应该调用哪个方法。3、重写遵循所谓“运行期绑定”,即在运行的时候,根据引用变量所指向的实际对象的类型来调用方法4、因为在编译期已经确定调用哪个方法,所以重载并不是多态。而重写是多态。重载只是一种语言特性,是一种语法规则,与多态无关,与面向对象也无关。(注:严格来说,重载是编译时多态,即静态多态。但是,Java中提到的多态,在不特别说明的情况下都指动态多态)
https://www.xilidou.com/2018/01/22/merge-request/
在高并发系统中,我们经常遇到这样的需求:系统产生大量的请求,但是这些请求实时性要求不高。我们就可以将这些请求合并,达到一定数量我们统一提交。最大化的利用系统性IO,提升系统的吞吐性能。
所以请求合并框架需要考虑以下两个需求:
- 当请求收集到一定数量时提交数据
- 一段时间后如果请求没有达到指定的数量也进行提交
- ScheduledThreadPoolExecutor
- 阻塞队列
- 线程安全的参数
- LockSupport的使用
- 既然我们的系统是在高并发的环境下使用,那我们肯定不能使用,普通的
ArrayList
来持有。我们可以使用阻塞队列来持有需要合并的请求。 - 我们的数据结构需要提供一个 add() 的方法给外部,用于提交数据。当外部add数据以后,需要检查队列里面的数据的个数是否达到我们限额?达到数量提交数据,不达到继续等待。
- 数据结构还需要提供一个timeOut()的方法,外部有一个计时器定时调用这个timeOut方法,如果方法被调用,则直接向远程提交数据。
- 条件满足的时候线程执行提交动作,条件不满足的时候线程应当暂停,等待队列达到提交数据的条件。所以我们可以考虑使用
LockSupport.park()
和LockSupport.unpark
来暂停和激活操作线程。
通常我们遇到定时相关的需求,首先想到的应该是使用
ScheduledThreadPoolExecutor
定时来调用FlushThread 的 timeOut 方法,如果你想到的是 Thread.sleep()
…那需要再努力学习,多看源码了。
我们使用的
FlushThread
实现了 Runnable
所以我们可以考虑使用线程池来持有多个FlushThread
。
在写BaseDao 之类的代码的时候,经常会遇到获取泛型T的class的情况?我们发现并没有
T.class
这种写法,那怎么办呢?想起之前写的Hibernate 里面有相关的代码。通过反射获取T的class
|
|
总体思路,因为两个list从不同服务里面获取。有可能两个服务出于健壮性的考虑会抛弃某些查询不到的对象,所以两个list的长度有可能不一致。所以使用一个Map 作为索引。
如果直接写代码会相当繁琐。如果使用 Java 8 的新特性
如果直接写代码会相当繁琐。如果使用 Java 8 的新特性
Lamabda
和stream api
就能快速写出代码。
|
|
这样merge的代码简洁明了。
https://dzone.com/articles/package-by-layer-for-spring-projects-is-obsoleteWhen I Google “package by layer” vs. “package by feature” or “folder by type” vs. “folder by feature”, there seems to be a growing camp of proponents of the “by feature” structure. I am in this camp, too.
https://dzone.com/articles/prefer-systemlineseparator-for-writing-system-depe
A number of classes in the base module use System.getProperty("line.separator") and could use the more efficient System.lineSeparator() to simplify the code and improve performance.
As the "Description" in JDK-8198645 states, use of
System.lineSeparator()
is simpler to use and more efficient than System.getProperty("line.separator")
. A recent message on the core-libs-dev mailing listprovides more details and Roger Riggs writes in that message that System.lineSeparator()
"uses the line separator from System instead of looking it up in the properties each time."
The performance benefit of using
System.lineSeparator()
over using System.getProperty("line.separator")
is probably not all that significant in many cases. However, given its simplicity, there's no reason not to gain a performance benefit (even if tiny and difficult to measure in many cases) while writing simpler code. One of the drawbacks to the System.getProperty(String)
approach is that one has to ensure that the exactly matching property name is provided to that method. With String
-based APIs, there's always a risk of spelling the string wrong (I have seen "separator" misspelled numerous times as "seperator"), using the wrong case, or accidentally introducing other typos that prevent exact matches from being made.
Lots of classes need to use System.getProperty("line.separator")
. Many don't do it right because you need to use a doPrivileged block whenever you read a system property. Yet it is no secret — you can divine the line separator even if you have no trust with the security manager.
An interesting side note related to the addition of
System.lineSeparator()
in JDK 7 is that the Javadoc at that time did not indicate that the method was new to JDK 7.https://dzone.com/articles/yet-4-more-techniques-for-writing-better-java
1. Validate Arguments With Standard Methods
this.engine = Objects.requireNonNull(engine, "Engine cannot be null");
this.transmission = Objects.requireNonNull(transmission, "Transmission cannot be null");
requireNonNull(T obj, Supplier<String> messageSupplier)
: Throws an NPE with a message generated by themessageSupplier
argument if the supplied object is null; the message is generated at the time the NPE is thrown; this method should be used when the message for the exception can be costly to create (and should therefore only be created if an NPE is thrown)requireNonNullElse(T obj, T defaultObj)
: Returns the supplied object if it is not null or returns the supplied default value otherwise
https://dzone.com/articles/5-hidden-secrets-in-java
A good guess would be
5. Enum Interface Implementation5
again, but if we run the above code, we see 8
printed to standard output. The reason behind this seeming bug is the Unicode character \u000d
; this character is actually a Unicode carriage return, and Java source code is consumed by the compiler as Unicode formatted text files. Adding this carriage return pushes the assignment value = 8
to the line directly following the comment, ensuring that it is executed. One of the limitations of enumerations (enums) compared to classes in Java is that enums cannot extend another class or enum.
We can, however, have our enum implement an interface and provide an implementation for its abstract methods
https://dzone.com/articles/java-using-immutable-classes-for-concurrent-programming
https://dzone.com/articles/3-things-every-java-developer-should-stop-doing
public List<User> getUsers() {
User[] usersFromDb = getUsersFromDatabase();
if (usersFromDb == null) {
// No users found in database
return Collections.emptyList();
}
else {
return Arrays.asList(usersFromDb);
}
}
}
3. Creating Indiscriminate Getters and Setters
What normally occurs in practice is that every private field is given a pair of getters and setters, exposing the internals of the class to external entities. This can cause some serious issues, especially if the private fields are mutable. This is not only a problem with setters but even when only a getter is present
In this case, we have changed the underlying value of the
Instead, adding Foo
object without informing the Bar
object. This can cause some serious problems if the value that we provided the Foo
object breaks an invariant of the Bar
object. For example, if we had an invariant that stated the value of Foo
could not be negative, then the above snippet silently breaks this invariant without notifying the Bar
object. When the Bar
object goes to use the value of its Foo
object, things may go south very quickly, especially if the Bar
object assumed that the invariant held since it did not expose a setter to directly reassign the Foo
object it held. This can even cause failure to a system if data is severely alteredfinal
to a field only ensures that the field itself is not reassigned (i.e. we cannot create a setter for that field). It does not stop the state of the object itself from being changed.It is important to note that if the fields of the class are non-primitive, a client can modify the underlying object as we saw above. Thus, immutable objects should return defensive copies of these objects, disallowing clients to modify the internal state of the immutable object. Note, though, that defensive copying can reduce performance since a new object is created each time the getter is called. This issue should not be prematurely optimized (disregarding immutability for the promise of possible performance increases), but it should be noted
Immutability also brings with it some very important advantages, such as the ability of the class to be easily used in a multi-threaded context (i.e. two threads can share the object without fear that one thread will alter the state of the object while the other thread is accessing that state). In general, there are many more instances that we can create immutable classes than we realize at first: Many times, we add getters or setters out of habit.
@SuppressWarnings("PMD.AvoidUsingHardCodedIP")
https://stackoverflow.com/questions/10508107/why-call-super-in-a-constructor
There is an implicit call to
https://blog.jooq.org/2017/07/14/dont-extract-everything-into-a-method/super()
with no arguments for all classes that have a parent - which is every user defined class in Java - so calling it explicitly is usually not required. However, you mayuse the call to super()
with arguments if the parent's constructor takes parameters, and you wish to specify them. Moreover, if the parent's constructor takes parameters, and it has no default parameter-less constructor, you will need to call super()
with argument(s).Junit throws AssertionError.
Java would still execute finally even if the block throws Error.
https://www.quora.com/What-is-meant-by-fall-through-with-respect-to-switch-case-blocks-in-Java
The one thing I will add is that usually this type of "fallthrough" is either an accident (missing break statement) or not what was planned by the developer.
My personal preference is to avoid relying on fallthrough logic as it can create brittle code as it can be easy to disrupt the intended logic.
http://www.dummies.com/programming/java/how-to-use-fall-through-to-your-advantage-in-java-programming/
switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: numberOfDays = 31; break; case 4: case 6: case 9: case 11: numberOfDays = 30; break; case 2: System.out.print("Leap year (true/false)? "); isLeapYear = keyboard.nextBoolean(); if (isLeapYear) { numberOfDays = 29; } else { numberOfDays = 28; } }
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
H Hour in day (0-23)
h Hour in am/pm (1-12)
M Month in year
m Minute in hour
y Year
Y Week year
http://www.maheshsubramaniya.com/article/understanding-how-jars-are-loaded-into-jvm-from-a-directory.html
EXT3 file system hash the filenames and places the entry in the directory level inode table.
readdir() returning filenames in a hash-sorted order, so that reads from the inode table would be done in a random order.So now you got an understanding of what directory ordering will look like.
So if your one machine load jars as
jar1.jar, jar2.jar
, another Linux machine with same OS release may load as jar2.jar,jar1.jar
or may be same order as the other machine. Random.Since it is random, you cannot expect the same ordering in another machine with EXT3 file system.
Why is this important to understand?
With the usage of Maven, developers tend to miss to verify the list of jars gets packaged into a web application. When maven pulls the dependencies and the dependencies uses two different versions same component, sayjavax.mail 1.3,1.4
then EXT3 file system doesn’t guarantee the order of jar loaded.So always exercise caution and do review your
lib/
folder to see what jars are pulled and packaged by your maven or any other packaging tool you use.记一次微服务jvm加载jar顺序机制导致的bug
jvm加载jar包顺序问题,然后又深入下去发现是jvm在不同机器上加载jar包顺序与文件系统存在关系,基本就能确定问题。jvm在linux通过jar文件在文件系统中生成顺序来进行加载,在linux底层是inode数据机构,详见Jvm加载jar包的顺序,这篇文章有详细记录,介绍了jvm在linux下加载jar方式。文章作者与笔者遇到类似问题。
使用-XX:+TraceClassPaths或者在服务器上执行jinfo时,都能得到classpath包含的jar包,例如:
java.class.path = local/aaa/lib/spring-data-redis-1.8.3.RELEASE.jar:/usr/local/aaa/lib/spring-tx-4.3.8.RELEASE.jar:/usr/local/aaa/lib/spring-jdbc-4.3.7.RELEASE.jar:/usr/local/aaa/lib/classmate-1.3.1.jar:/usr/local/aaa/lib/javax.servlet-api-3.1.0.jar:/usr/local/aaa/lib/mongodb-driver-3.4.2.jar:/usr/local/aaa/lib/xml-apis-2.0.2.jar:/usr/local/aaa/lib/ufc-api-utils-2.0.0.jar:/usr/local/aaa/lib/log4j-over-slf4j-1.7.25.jar:/usr/local/aaa/lib/tomcat-embed-websocket-8.5.14.jar:...
这些jar的顺序不同的机器总是不一样的,平时没有问题,所以也没有细想过,这些jar包的顺序为什么会不一样的
这个问题在多台服务器上都出现了,所以搜集多台的输出后可以确认这个规律,其实在结尾连接中代码记录里也可以看出,如果有多个同名的类只会加载其中第一个。在不出问题的服务器上commons-codec-1.10.jar是在http-1.1.0.jar之前加载的,而出问题的服务器正好相反。
/usr/lib/jvm/java-8-oracle/jre/lib/rt.jar!/sun/misc/URLClassPath.class中的private ArrayList path有所有加载的jar的URL。这个类里还有每个jar的loader:ArrayList<URLClassPath.Loader> loaders,jar路径和jarLoader的映射:HashMap<String, URLClassPath.Loader> lmap。lmap通过private synchronized URLClassPath.Loader getLoader(int var1)方法从Stack urls中弹出的jar来构造loader并加入映射的。有两个URLClassLoader加载不同的URLClassPath实例,一个只有jre/lib下的几个jar,一个有所有的。不过这都不重要,这些jar都是从classpath加载的。于是我在几个服务器上用jinfo输出了java.class.path,并对比了一下发现正常服务器和服务器中,这两个jar的顺序果然是不一样的。那么我估计问题是出现jvm对java.class.path赋值的前面了,或许是操作系统什么的。
http://insightfullogic.com/2015/Jan/19/given-when-then-java/Given: cafe.setCoffeesRemaining(1); When: cafe.serveCoffee(); Then: assertFalse(cafe.canServeCoffee());https://blog.jooq.org/2013/08/20/10-subtle-best-practices-when-coding-java/
The Rule: Whenever you implement logic using before/after, allocate/free, take/return semantics, think about whether the after/free/return operation should perform stuff in the inverse order.
But nonetheless, destructors have an interesting trait to them. It often makes sense to free memory in the inverse order of allocation. Keep this in mind in Java as well, when you’re operating with destructor-like semantics:
- When using @Before and @After JUnit annotations
- When allocating, freeing JDBC resources
- When calling super methods
1
2
3
4
5
6
7
8
9
10
11
| @Override public void beforeEvent(EventContext e) { super .beforeEvent(e); // Super code before my code } @Override public void afterEvent(EventContext e) { // Super code after my code super .afterEvent(e); } |
interface
EventListener {
// Bad
default
void
message(String message) {
message(message,
null
,
null
);
}
// Better?
void
message(
String message,
Integer id,
MessageSource source
);
}
But much better than polluting your SPI with dozens of methods, use a context object (or argument object) just for this purpose.
1
2
3
4
5
6
7
8
9
10
| interface MessageContext { String message(); Integer id(); MessageSource source(); } interface EventListener { // Awesome! void message(MessageContext context); } |
You can evolve the MessageContext API much more easily than the EventListener SPI as fewer users will have implemented it.
The Rule: Whenever you specify an SPI, consider using context / parameter objects instead of writing methods with a fixed amount of paramete
Remark: It is often a good idea to also communicate results through a dedicated MessageResult type, which can be constructed through a builder API. This will add even more SPI evolution flexibility to your SPI.
3. Avoid returning anonymous, local, or inner classes
But you should not use anonymous, local, or inner classes too often for a simple reason: They keep a reference to the outer instance. And they will drag that outer instance to wherevery they go, e.g. to some scope outside of your local class if you’re not careful. This can be a major source for memory leaks, as your whole object graph will suddenly entangle in subtle ways.
The Rule: Whenever you write an anonymous, local or inner class, check if you can make it static or even a regular top-level class. Avoid returning anonymous, local or inner class instances from methods to the outside scope.
Remark: There has been some clever practice around double-curly braces for simple object instantiation:
1
2
3
4
| new HashMap<String, String>() {{ put( "1" , "a" ); put( "2" , "b" ); }}
|
What would otherwise be a completely independent HashMap instance now keeps a reference to the outer instance, whatever that just happens to be. Besides, you’ll create an additional class for the class loader to manage.
4. Start writing SAMs now! - Define methods that accepts function interface instance
Your API consumers should be able to chain methods whenever applicable:
1
| initialise(someArgument).calculate(data).dispatch(); |
In the above snippet, none of the methods should ever return null. In fact, using null’s semantics (the absence of a value) should be rather exceptional in general
n libraries like jQuery (or jOOX, a Java port thereof), nulls are completely avoided as you’re always operating on iterable objects. Whether you match something or not is irrelevant to the next method call.
Nulls often arise also because of lazy initialisation. In many cases, lazy initialisation can be avoided too, without any significant performance impact. In fact, lazy initialisation should be used carefully, only. If large data structures are involved.
https://github.com/jOOQ/jOOX/blob/master/jOOX/src/test/java/org/joox/test/JOOXTest.javaint $ = 1;
$(document).find("orders").children().eq(4).append("<paid>true</paid>");
An array of strings naming the files and directories in the directory denoted by this abstract pathname. The array will be empty if the directory is empty. Returns null if this abstract pathname does not denote a directory, or if an I/O error occurs.
Most I/O operations produce IOExceptions, but this one returns null. Null cannot hold any error message indicating why the I/O error occurred. So this is wrong in three ways:
- Null does not help in finding the error
- Null does not allow to distinguish I/O errors from the File instance not being a directory
- Everyone will keep forgetting about null, here
In collection contexts, the notion of “absence” is best implemented by empty arrays or collections. Having an “absent” array or collection is hardly ever useful, except again, for lazy initialisation.
7. Avoid state, be functional
The Rule: Arrays or Collections should never be null.
Implement more of a functional style. Pass state through method arguments. Manipulate less object state.
This specifically applies for static methods, where “overriding” (actually, shadowing) hardly ever makes sense. I’ve come across a very bad example of shadowing static methods in Apache Tika, recently. Consider:
TikaInputStream extends TaggedInputStream and shadows its static get() method with quite a different implementation.
Unlike regular methods, static methods don’t override each other, as the call-site binds a static method invocation at compile-time. If you’re unlucky, you might just get the wrong method accidentally.
9. Try to make methods final by default- If you do need to override a method (do you really?), you can still remove the final keyword
- You will never accidentally override any method anymore
More importantly, you may think that you can overload the above method, but you cannot:
1
2
| void acceptAll(T... all); void acceptAll(String message, T... all); |
This looks as though you could optionally pass a String message to the method. But what happens to this call here?
1
| acceptAll( "Message" , 123 , "abc" ); |
The compiler will infer
<? extends Serializable & Comparable<?>>
for T
, which makes the call ambiguous!
So, whenever you have an “accept-all” signature (even if it is generic), you will never again be able to typesafely overload it. API consumers may just be lucky enough to “accidentally” have the compiler chose the “right” most specific method. But they may as well be tricked into using the “accept-all” method or they may not be able to call any method at all.
The Rule: Avoid “accept-all” signatures if you can. And if you cannot, never overload such a method
https://blog.jooq.org/2015/02/05/top-10-easy-performance-optimisations-in-java/
Don’t call expensive methods in an algorithms “leaf nodes”, but cache the call instead, or avoid it if the method contract allows it.
Use primitives and the stack
1
2
| // Goes to the heap Integer i = 817598 ; |
… by this:
1
2
| // Stays on the stack int i = 817598 ; |
Things get worse when you’re using arrays:
1
2
| // Three heap objects! Integer[] i = { 1337 , 424242 }; |
… by this:
1
2
| // One heap object. int [] i = { 1337 , 424242 }; |
There is an exception to this rule:
boolean
and byte
have few enough values to be cached entirely by the JDK. You can write:
1
2
3
4
5
| Boolean a1 = true ; // ... syntax sugar for: Boolean a2 = Boolean.valueOf( true ); Byte b1 = ( byte ) 123 ; // ... syntax sugar for: Byte b2 = Byte.valueOf(( byte ) 123 ); |
The same is true for low values of the other integer primitive types, including
char
, short
, int
, long
.
But only if you’re auto-boxing them, or calling
TheType.valueOf()
, not when you call the constructor!Never call the constructor on wrapper types, unless you really want a new instance
Optimise your hashCode() and equals() methods
public boolean equals(Object that) { if ( this == that) { return true ; } // [#2144] Non-equality can be decided early, // without executing the rather expensive // implementation of AbstractQueryPart.equals() if (that instanceof AbstractTable) { if (StringUtils.equals(name, (((AbstractTable<?>) that).name))) { return super .equals(that); } return false ; } return false ; } |
First thing: Always (not only in a N.O.P.E. branch) abort every
equals()
method early, if:this == argument
this "incompatible type" argument
Note that the latter condition includes
argument == null
, if you’re using instanceof
to check for compatible typesA version is a tuple of 4 numbers:
Major.Minor.Bugfix.Hotfix
Major is incremented in case of big and/or non-backward compatible changes.
Minor is incremented for any change that does not require a major version bump and is a bigger change than a simple bugfix.
Bugfix is incremented to indicate a bug fixing change that is small and self-contained.
Hotfix is normally 0 and is incremented when a change is made to a previously released artifact.
Before the annotation, since the annotation is code that "belongs" to the class. See examples with javadoc in the official documentation.
Here's random example I found in another official Java page:
/**
* Delete multiple items from the list.
*
* @deprecated Not for public use.
* This method is expected to be retained only as a package
* private method. Replaced by
* {@link #remove(int)} and {@link #removeAll()}
*/
@Deprecated public synchronized void delItems(int start, int end) {
...
@Deprecated public final void stop() { synchronized (this) {
Use the
toArray(T[] arr)
method..getMap(locations.toArray(new WorldLocation[locations.size()]))
(
toArray(new WorldLocation[0])
also works, but you would allocate a zero length array for no reason.)
Here's a complete example:
public static void method(String... strs) {
for (String s : strs)
System.out.println(s);
}
...
List<String> strs = new ArrayList<String>();
strs.add("hello");
strs.add("wordld");
method(strs.toArray(new String[strs.size()]));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Java: Passing a list as argument to a vararg method
The parameter type
String...
is equivalent to String[]
so just use the List.toArray(T[] arr)
method to convert the list to an array. For example:varargMethod(strList.toArray(new String[strList.size()]));
https://dzone.com/articles/an-introduction-to-hollow-jars
A typical Hollow JAR deployment then will consist of two files: the Hollow JAR itself and the WAR file that holds the application code. The Hollow JAR is then executed referencing the WAR file, and from that point on the two files run much as an UberJAR would.
At first blush, it might seem unproductive to have the two files that make up a Hollow JAR deployment instead of the single file that makes up the UberJAR, but there are some benefits.
The main benefit comes from the fact that the JAR component of the Hollow JAR deployment pair won’t change all that frequently. While you could expect to deploy new versions of the WAR half of the deployment multiple times per day, the JAR half will remain static for weeks or months. This is particularly useful when building up layered container images, as only the modified WAR file needs to be added as a container image layer.
Likewise, you may also reduce build times with technologies like AWS autoscaling groups. Because the JAR file doesn’t change often, this can be baked into an AMI, while the WAR file can be downloaded as an EC2 instance is deployed through the scripting placed into an EC2 user data field.
The
--hollow
argument instructs SwarmTool to build a Hollow JAR that does not embed the WAR file. If we left this argument off, the WAR file would be embedded in the resulting JAR file, creating an UberJAR instead of a Hollow JAR.http://www.java2novice.com/java-annotations/marker/
|
@Retention(RetentionPolicy.RUNTIME)
@interface MyMarkerAnnot{}
public class MyMarkerAnnotation {
@MyMarkerAnnot
public void myAnnotationTestMethod(){
try {
Class<? extends MyMarkerAnnotation> cls = this.getClass();
Method mth = cls.getMethod("myAnnotationTestMethod");
if(mth.isAnnotationPresent(MyMarkerAnnot.class)){
System.out.println("Hey... marker annotation is present.");
} else {
System.out.println("Marker annotation is not present.");
}
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
https://stackoverflow.com/questions/33170109/difference-between-optional-orelse-and-optional-orelseget
I would say the biggest difference between
orElse
and orElseGet
comes when we want to evaluate something to get the new value in the else
condition.
Consider this simple example -
// oldValue is String type field that can be NULL
String value;
if (oldValue != null) {
value = oldValue;
} else {
value = apicall().value;
}
Now let's transform the above example to using
Optional
along with orElse
,// oldValue is Optional type field
String value = oldValue.orElse(apicall().value);
Now let's transform the above example to using
Optional
along with orElseGet
,// oldValue is Optional type field
String value = oldValue.orElseGet(() -> apicall().value);
When
orElse
is invoked, the apicall().value
is evaluated and passed to the method. Whereas, in the case of orElseGet
the evaluation only happens if the oldValue
is empty. orElseGet
allows lazy evaluation.using Enums as parameters to indicate method behavior
So, he went about and changed the int to the Order Enum like this:
https://dzone.com/articles/java-holiday-calendar-2016-day-21-concatenate-java// Works for a small number of streams
Stream.concat(
preamble,
Stream.concat(firstAmendment, epilogue)
)
.forEach(System.out::println);
// Works for any number of streams
Stream.of(preamble, firstAmendment, epilogue)
.flatMap(Function.identity())
.forEach(System.out::println);
As we all know, Java will occasionally clean up the heap (i.e. invoke its Garbage Collector or GC for short) and remove objects that are no longer used. As the heap grows, so will the time it takes to clean it up. Eventually, the GC will take seconds or minutes, and we have hit "the GC wall". Historically, this was a problem for heaps above 10 GB of data, but nowadays we can have larger heaps. How big depends on a vast number of factors.
One way of reducing GC impact is to store data off heap, where the GC is not even looking. This way, we can grow to any data size without caring about the GC. The drawback is that we have to manage our memory manually and also provide a means of converting data back and forth between the two memory regions. In general, this is a bit tricky, but if we limit ourselves to the primitive types like int, long, double, and the likes, it is fairly easy.
public final class OffHeapIntArray implements Iterable<Integer> {
private final IntBuffer buffer;
private final int length;
public OffHeapIntArray(int length) {
if (length < 0) {
throw new IllegalArgumentException();
}
this.length = length;
/* Allocates memory off heap */
this.buffer = ByteBuffer.allocateDirect(length * Integer.BYTES)
.asIntBuffer();
}
public int get(int index) {
return buffer.get(index);
}
public void set(int index, int value) {
buffer.put(index, value);
}
public int length() {
return length;
}
public PrimitiveIterator.OfInt iterator() {
return new Iter();
}
public void forEach(Consumer<? super Integer> action) {
for (int i = 0; i < length; i++) {
action.accept(i);
}
}
public Spliterator.OfInt spliterator() {
return Spliterators.spliterator(iterator(), length,
Spliterator.SIZED
| Spliterator.SUBSIZED
| Spliterator.NONNULL
| Spliterator.CONCURRENT
);
}
public IntStream stream() {
return StreamSupport.intStream(spliterator(), false);
}
private final class Iter implements PrimitiveIterator.OfInt {
private int currentIndex;
public Iter() {
currentIndex = 0;
}
public int nextInt() {
if (hasNext()) {
return get(currentIndex++);
}
throw new NoSuchElementException();
}
public void forEachRemaining(IntConsumer action) {
while (currentIndex < length) {
action.accept(get(currentIndex++));
}
}
public boolean hasNext() {
return currentIndex < length;
}
public Integer next() {
return nextInt();
}
}
}
这个注解是 HotSpot VM 标准的注解,被它标记的方法表明它为 HotSpot VM 的固有方法, HotSpot VM 会对其做一些增强处理以提高它的执行性能,比如可能手工编写汇编或手工编写编译器中间语言来替换该方法的实现。虽然这里被声明为 native 方法,但是它跟 JDK 中其他的本地方法实现地方不同,固有方法会在 JVM 内部实现,而其他的会在 JDK 库中实现。在调用方面,由于直接调用 JVM 内部实现,不走常规 JNI lookup,所以也省了开销。