-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JsonObject optimization #4994
JsonObject optimization #4994
Conversation
1) use JDK Map.entry(key,value) instead of self-made Entry class One caveat: Map.entry disallows null keys and values (Attempts to create Map.Entry using a null key or value result in NullPointerException) 2) (Linked)HashMap has DEFAULT_LOAD_FACTOR = 0.75f: if you create it with initialCapacity=X and put X items into it then HashMap resizes (with new internal array allocation and re-hash). One has to create HashMap with initialCapacity=X/0.75 e.g. for 10 keys initialCapacity must be at least 14 3) better inheritance: equals `if (getClass() != o.getClass()) return false;` rejects subclasses. if (!(o instanceof JsonObject)) return false allows subclasses and checks for null
No problems with
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK with a few comments
@@ -122,7 +122,7 @@ public static JsonObject of(String k1, Object v1) { | |||
* @return a JsonObject containing the specified mappings. | |||
*/ | |||
public static JsonObject of(String k1, Object v1, String k2, Object v2) { | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(2)); | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(4)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonObject obj = new JsonObject(new LinkedHashMap<>(4)); | |
JsonObject obj = new JsonObject(new LinkedHashMap<>(3)); |
According to https://guava.dev/releases/21.0/api/docs/src-html/com/google/common/collect/Maps.html#line.291
@@ -105,7 +105,7 @@ public static JsonObject of() { | |||
* @return a JsonObject containing the specified mapping. | |||
*/ | |||
public static JsonObject of(String k1, Object v1) { | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(1)); | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(3)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonObject obj = new JsonObject(new LinkedHashMap<>(3)); | |
JsonObject obj = new JsonObject(new LinkedHashMap<>(2)); |
According to https://guava.dev/releases/21.0/api/docs/src-html/com/google/common/collect/Maps.html#line.291
@@ -166,7 +166,7 @@ public static JsonObject of(String k1, Object v1, String k2, Object v2, String k | |||
*/ | |||
public static JsonObject of(String k1, Object v1, String k2, Object v2, String k3, Object v3, | |||
String k4, Object v4) { | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(4)); | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(7)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonObject obj = new JsonObject(new LinkedHashMap<>(7)); | |
JsonObject obj = new JsonObject(new LinkedHashMap<>(6)); |
https://guava.dev/releases/21.0/api/docs/src-html/com/google/common/collect/Maps.html#line.291
@@ -193,7 +193,7 @@ public static JsonObject of(String k1, Object v1, String k2, Object v2, String k | |||
*/ | |||
public static JsonObject of(String k1, Object v1, String k2, Object v2, String k3, Object v3, | |||
String k4, Object v4, String k5, Object v5) { | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(5)); | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(8)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonObject obj = new JsonObject(new LinkedHashMap<>(8)); | |
JsonObject obj = new JsonObject(new LinkedHashMap<>(7)); |
https://guava.dev/releases/21.0/api/docs/src-html/com/google/common/collect/Maps.html#line.291
@@ -294,7 +294,7 @@ public static JsonObject of(String k1, Object v1, String k2, Object v2, String k | |||
public static JsonObject of(String k1, Object v1, String k2, Object v2, String k3, Object v3, | |||
String k4, Object v4, String k5, Object v5, String k6, Object v6, | |||
String k7, Object v7, String k8, Object v8) { | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(8)); | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(12)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonObject obj = new JsonObject(new LinkedHashMap<>(12)); | |
JsonObject obj = new JsonObject(new LinkedHashMap<>(11)); |
https://guava.dev/releases/21.0/api/docs/src-html/com/google/common/collect/Maps.html#line.291
@@ -334,7 +334,7 @@ public static JsonObject of(String k1, Object v1, String k2, Object v2, String k | |||
public static JsonObject of(String k1, Object v1, String k2, Object v2, String k3, Object v3, | |||
String k4, Object v4, String k5, Object v5, String k6, Object v6, | |||
String k7, Object v7, String k8, Object v8, String k9, Object v9) { | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(9)); | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(14)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonObject obj = new JsonObject(new LinkedHashMap<>(14)); | |
JsonObject obj = new JsonObject(new LinkedHashMap<>(13)); |
https://guava.dev/releases/21.0/api/docs/src-html/com/google/common/collect/Maps.html#line.291
@@ -378,7 +378,7 @@ public static JsonObject of(String k1, Object v1, String k2, Object v2, String k | |||
String k4, Object v4, String k5, Object v5, String k6, Object v6, | |||
String k7, Object v7, String k8, Object v8, String k9, Object v9, | |||
String k10, Object v10) { | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(10)); | |||
JsonObject obj = new JsonObject(new LinkedHashMap<>(16)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonObject obj = new JsonObject(new LinkedHashMap<>(16)); | |
JsonObject obj = new JsonObject(new LinkedHashMap<>(14)); |
https://guava.dev/releases/21.0/api/docs/src-html/com/google/common/collect/Maps.html#line.291
@@ -1160,14 +1160,11 @@ public String toString() { | |||
|
|||
@Override | |||
public boolean equals(Object o) { | |||
// null check |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to remove this, unless it is proved it slows down things
// self check | ||
if (this == o) | ||
return true; | ||
// type check and cast | ||
if (getClass() != o.getClass()) | ||
// type check, cast and null check |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to change this, we don't plan to support subclasses
@tsegismont I have indeed made initial capacity bigger than required, but only to prevent resize for the next 1-3 user’s puts. Do you have any statistics how JsonObject is used? I am not sure what is better 🤷♀️ Following question: does JsonObject really needs LinkedHashMap? LinkedHashMap uses more memory than HashMap. The only place where you see the difference is interator(). About equals: why not make it final, then? |
1) use MAP_CREATOR 2) LinkedHashMap → HashMap (can be changed in MAP_CREATOR) 3) better initial capacity
@tsegismont Please review again: I have found a very interesting solution. |
better spliterator() and stream() implementations Use Spliterator flags and map.size() to make them more performant
@@ -1158,16 +1182,21 @@ public String toString() { | |||
return encode(); | |||
} | |||
|
|||
/** | |||
How to Write an Equality Method in Java |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you remove this reference to this article ? it's not needed
How to Write an Equality Method in Java | ||
https://www.artima.com/articles/how-to-write-an-equality-method-in-java | ||
*/ | ||
protected boolean canEqual(Object other) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you actually remove this ? we don't actually add such contract for json object.
json object is not meant to be subclasses (although sometimes it is) and we don't encourage it.
// todo replace with HashMap? → Less memory usage, but random keys order, but .stream().sorted()? | ||
// immutable Map.of javadoc: The iteration order of mappings is unspecified and is subject to change | ||
@SuppressWarnings("rawtypes") | ||
public static final IntFunction<Map> MAP_CREATOR = size -> new LinkedHashMap(size < 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please inline that directly in map(int)
, we don't need to have one static method that delegates to one static field
@tsegismont @vietj I will redo this PR as a single commit with all fixes. |
@magicprinc please keep only the following changes in your PR:
We don't need a method for dynamic computation of map capacity. For |
I did my best #5001 |
thanks, you didn't need to close the PR for a new one, you could have force pushed your branch instead with the rebased version, that would have updated the PR in place that is preferable because with a new PR with lose the context of the review in progress. |
@vietj I didn't know such thing exists. Thank You! |
One caveat: Map.entry disallows null keys and values (Attempts to create Map.Entry using a null key or value result in NullPointerException), but it is used in JsonObject iterator only and the iterator doesn't wrap null values in new Map.Entry
e.g. for 10 keys initialCapacity must be at least 14
You can see it yourself under the debugger
if (getClass() != o.getClass()) return false
rejects subclassesif (!(o instanceof JsonObject)) return false
allows subclasses and checks fornull