-
Notifications
You must be signed in to change notification settings - Fork 18
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
Use JDK UUID#fromString for Java >= 15 #15
base: main
Are you sure you want to change the base?
Conversation
Java 8
Java 17
|
Java 17 (before this change):
|
I would second this. Comparing the actual Open JDK 17 implementation with the FastUUID implementation, I see only small differences. As such, I would recommend people to use the build-in version instead. Perhaps you should go even one step further, and you should declare this utility 'deprecated' for OpenJDK 17 onward. |
@KevinAtSesam deprecated for OpenJDK >= 15, though for the foreseeable future, I think projects will still be targeting Java 8 or 11, so this is still a pretty useful library. |
@KevinAtSesam also, this library can handle any I mean, pretty minor use-case, though, but still a difference. |
Sounds good to me. Just glad to see that Jdk 17 made such an improvement. |
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.
Thank you for the contribution! I have a couple questions and suggestions, but agree that this is a good thing to be doing in general.
One additional request that doesn't fit neatly on any single line of code: since we're making Java 15 the cutoff for some of these features, could you please share benchmarks form Java 15? (EDIT: to be clear, I really appreciate the benchmark results from Java 17, but matching the benchmarks to the cutoff version would be great for posterity!)
Thanks very much!
<scope>test</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.openjdk.jmh</groupId> | ||
<artifactId>jmh-core</artifactId> | ||
<version>1.21</version> | ||
<version>1.32</version> |
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.
Note to self: we should probably pull this out into a property so we don't have to change the version in three different places. Let's definitely leave that for a separate effort, though.
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.
I can do that, no problem. Will extract when I get the chance to open it again on IntelliJ.
* @throws IllegalArgumentException if the given string does not conform to the string representation as | ||
* described in {@link UUID#toString()} | ||
*/ | ||
public static UUID parseUUID(final String uuidString) { |
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.
I think I'm missing something: why do we need this if we also have parseUUID(CharSequence)
, which also checks if the CharSequence
is a String
?
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.
Because JDK's method only works with String
.
So we can:
- Change the signature of our method to
parseUUID(String)
and possibly break compatibility; - Call
CharSequence#toString()
but that will lead to memory copies in any non-String
objects that implementCharSequence
; - Add a method that uses
String
(so it can be passed to JDK's in case we're running on >= 15) and keep theCharSequence
there too and shared the common code path between the two (for JDKs prior to 15, butCharSequence
would always go there since we don't want to copy memory); - Number 3 + we check if the
CharSequence
is aString
so we can pass it to JDK's, but we keep using our implementation in case it's not (since it performs closely anyway).
instanceof
has basically no cost on modern JVMs anyway, so I chose to go with 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.
Ah—I think I see where you're going here. If I can reword it to make sure we're on the same page, I think you're saying that you want to add a String
-specific variant because that will lower the cost of passing through to UUID#fromString
under Java 15 and newer.
If I'm understanding that right, I'd gently push back that I think it's okay to continue using fast-uuid's parser even under Java 15. My rationale is that if somebody is working with non-String
CharSequences
, they probably have some specific thing they're doing that means they want to avoid String
conversion in the first place, and using the sliiiiightly slower FastUuid#parseUUID(CharSequence)
will still be faster for those users than converting to a String
, then using the slightly faster UUID#fromString(String)
.
As you say, using instanceof
in FastUuid#parseUUID(CharSequence)
is a negligible cost, so most users would still get the benefits of using the built-in parser under Java 15 and newer, and it's only the oddballs (like me!) who have a CharSequence
-specific use case that would be staying in the fast-uuid space.
Does that make sense? Am I missing your point?
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.
It's more of a compile-time optimization and maybe being able to deal with JVMs where instanceof
isn't super-duper cheap.
If you upgrade from existing code to this, your compiler will link your calls that use String-typed references to the new method. So
String uuidString = someMethodThatReturnsString();
// this will now link directly to the String method instead of the CharSequence one without the user having to change any code
UUID id = FastUUID.parseUUID(uuidString);
CharSequence uuidChars = someMethodThatReturnsCharSequence();
// this will still link to the CharSequence method
UUID idFromCharSequence = FastUUID.parseUUID(uuidChars);
If uuidChars
happens to actually be a String, we can still leverage the speed boost by checking that and calling JDK's UUID#fromString
.
Providing the overload with String allows us to skip that step without the user changing any code because upon compilation, they'd link to the new method if the reference is String-typed.
A CharSequence reference to a CharSequence non-String object will still just use the existing parser just fine. There is no conversion involved.
I see this as a win-win change. The only downside is that FastUUID.parseUUID(null)
would not compile anymore. You'd have to cast the null to either CharSequence or String.
For someone using fast-uuid indirectly, the type-check to String inside the CharSequence overload still allows for the performance boost in Java 15 even without recompilation.
Sure. Will get benchmarks from 15 later today. |
Java 15 (AdoptOpenJDK HotSpot)
|
Thank you for the Java 15 benchmarks! Let's resolve the conversation about the |
@jchambers so, any news on that? |
Oops—sorry. This got lost in the holiday shuffle. I'll get back to this shortly. |
@jchambers hi there :) wanna figure out the situation with the I can also add the |
Explanation on the README