Specifically, it throws a NullPointerException if original is null. Yet the javadocs do not mention it.
I know, it says this constructor should not be necessary unless an explicit copy is needed, but I am writing copy constructors for some larger objects that contain Strings, and while it probably isn't strictly necessary to make an explicit copy, since everything else is getting an explicit copy in this case, I'm willing to pay a small price in inefficiency.
But shouldn't there be a throws in this javadoc?
From JavaTM 2 Platform Std. Ed. v1.4.2:
Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.
Strings are immutable. You do not want to create a String myString = new String("blah"); since this would result in a new object in heap. It is better to do String myString = "blah"; and link to the strings pool.
String myString = "blah";
String myOtherString = myString;
myOtherString = "";
// at this point myString == "blah"
NullPointerException is an unchecked exception so although if you're very pedantic, you can add a #throws line to the javadoc, it's better not to. It's assumed that if you pass null where it doesn't make sense, you get an NPE. (Unchecked exceptions are more often than not signal a coding error, rather than an exceptional but valid scenario.)
And new String( null ) doesn't make sense, as a constructor couldn't result in an exact "copy" of null.
Copying strings is totally unnecessary too as they're immutable.
The javadoc for this constructor says:
Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable
So you really shouldn't be calling it.
Also, I think it's reasonable to throw an NPE if you pass a null in
RuntimeException is reserved for exceptions that indicate incorrect use of an API (using a null object), which can occur anywhere in a Java program, so it's not particular to the String class (or any specific class)
The issue of the documentation has been addressed by the accepted answer.
I just want to respond to this comment ... which is probably the root of your problem.
But that assumes it doesn't make sense to pass null. Suppose you are copying some Object that has many data member fields, some of which are Strings, and which may or may not be null. In that case I want String(String) to return null, specifically, I want it to copy the null value.
That is not possible. The JLS specifically states that the new operation yields a new object and not a null.
If you want to be able to "create and return an object or null" you have to embed this logic in a factory method of some kind; e.g.
String myNewString(String s) {
return s == null ? s : new String(s);
}
But it is also worth noting that in most circumstances copying a String in Java is unnecessary and wasteful. You should only do this if your application is specifically making use of the object identity of the strings; i.e. that it uses == to compare string objects and depends on strings with the same characters comparing as false. (Applications that require that are pretty rare ...)
Related
The java.util.Objects class was extended with a number of new methods
Objects#requireNonNullElse
respectively
Objects#requireNonNullElseGet() in Java-9.
Both will return the first argument if it is non-null and otherwise returns the non-null second argument or the non-null value of supplier.get()
jshell> String nullStr = null;
nullStr ==> null
jshell> Objects.requireNonNullElse(nullStr,"lorem ipsum");
$13 ==> "lorem ipsum"
jshell> Objects.requireNonNullElseGet(nullStr,() -> "lorem ipsum");
$14 ==> "lorem ipsum"
But the new functionality overlaps with already existing in the Optional class Optional#orElse and Optional#orElseGet
jshell> Optional.ofNullable(nullStr).orElse("lorem ipsum");
$17 ==> "lorem ipsum"
jshell> Optional.ofNullable(nullStr).orElseGet(() -> "lorem ipsum");
$18 ==> "lorem ipsum"
The only difference between new methods in Objects and corresponding Optional methods is that second argument or value of supplier must be non-null otherwise Objects throws NPE:
jshell> Objects.requireNonNullElseGet(nullStr,() -> null);
| java.lang.NullPointerException thrown: supplier.get()
| at Objects.requireNonNull (Objects.java:246)
| at Objects.requireNonNullElseGet (Objects.java:321)
| at (#15:1)
jshell> Objects.requireNonNullElse(nullStr,null);
| java.lang.NullPointerException thrown: defaultObj
| at Objects.requireNonNull (Objects.java:246)
| at Objects.requireNonNullElse (Objects.java:301)
| at (#16:1)
versus Optional
jshell> Optional.ofNullable(nullStr).orElse(null);
$19 ==> null
jshell> Optional.ofNullable(nullStr).orElseGet(() -> null);
$20 ==> null
Why haven't the JDK developers updated existing methods in Optional
class?
Why haven't they introduced a new method (which will thrown
NPE if second argument is null) to Optional class?
What should we use now Optional or Objects?
Do new methods make Objects more preferable than Optional since they
will throw NPE immediately and not later on somewhere in the code
like with Optional?
If I have a legacy code, something like:
String str = null;
String result = str == null ? "other string" : str;
Which is just a simple check inside a method. And I would like to re-factor it using latest language features. Now having in mind the difference between Optional.orElse and Objects.requireNonNullOrElse which is preferable?
result = Optional.ofNullable(str).orElse("other string");
or
result = Objects.requireNonNullOrElse(str,"other string);
The shortest answer to your question "which is preferable?" is the all-time developer favorite "it depends" 😜 because Objects::requireNonNullElse and Optional cover different use cases.
The Two Alternatives
Before answering your questions I want to give some background on the two alternatives.
Objects::requireNonNullElse
Objects::requireNonNull makes sure that the result of the call is never null (hence the name). It is usually used to succinctly verify constructor or method arguments and allows readers to verify with a glance that the variable to which the return value is assigned can not be null.
So it would not only be weird for Objects::requireNonNullElse to suddenly allow null, it would also be borderline useless because:
// if requireNonNullGet would allow null as second argument,
// the following is true for all x (including null)
Objects.requireNonNullElse(x, null) == x
You might argue that it is different for requireNonNullElseGet because that might call a function that, depending on some state, might return null or not. That's true and I assume it was considered but the requireNonNull... API would be really weird if one of the three cases might actually allow the final result of the call to be null even though the name says required non null.
Optional
Optional was designed as a return argument in cases where returning null is very likely to cause NPEs (like for a Stream's terminal operation, where it was first used). Although some developers prefer to use it in more cases (compare Stephen Colebourne's pragmatic approach and my strict approach) no one really proposes using it as in your demonstration:
Optional.ofNullable(nullStr).orElse(null);
Optional.ofNullable(nullStr).orElseGet(() -> null);
Optional is a way to express in the type system that something might be missing - it is not meant as an alternative to if-null-checks. In that sense orElse or orElseGet are backdoors out of Optional back into the world of nullable types and sometimes null is just what you want to use if something's not there, so it makes sense for them to accept null as an argument (or the supplier's result).
Your Questions
Now we have what we need to answer your questions:
Why haven't the JDK developers updated existing methods in Optional class?
Conceptually that would go against what Optional should be used for. But, as others have mentioned, this would be a backwards incompatible change as calls to orElse(null) would suddenly throw exceptions.
Why haven't they introduced a new method (which will thrown NPE if second argument is null) to Optional class?
APIs are only extended if considerable improvements of existing code can be expected. I don't see that here. In many cases orElse gets an argument that the caller creates specifically as an alternative for empty optionals - there is rarely a need to make an extra check to verify it's not null. If you really have to, call orElse(requireNonNull(x)).
What should we use now Optional or Objects?
If you have a variable (be it local, an argument or a field) and you want to make sure it's not null, use Objects. If you want to return something, which may be null consider wrapping it in Optional. Be suspicious of code that creates an Optional (as opposed to getting one form a call) and unwraps it at the end of the same chain.
Do new methods make Objects more preferable than Optional since they will throw NPE immediately and not later on somewhere in the code like with Optional?
As I'm sure is clear by now, they cover different use cases. But let me address "and not later on somewhere in the code like with Optional": Whatever you do, make sure to check your desired nullablity property (can be null or not) in your code. Don't return something that you assume can not be null but it turns out to be because you didn't check. If that happens, it's not Optional's fault.
If I have a legacy code, something like:
String str = null;
String result = str == null ? "other string" : str;
Definitely Objects.requireNonNullOrElse(str,"other string"); and consider using static imports to make it more readable.
Why haven't the JDK developers updated existing methods in Optional class?
Because that would introduce a breaking change that would break many existing programs, and because the method should allow getting null if desired.
Why haven't they introduced a new method (which will thrown NPE if second argument is null) to Optional class?
Probably because that would make the API more convoluted and bloated for no significant advantage. You can still wrap the result with requireNonNull if you want to ensure your code doesn't return null unexpectedly.
What should we use now Optional or Objects?
If you need to extract a value out of an optional returned by a method, then use Optional's method. If you want to ensure preconditions are respected for the argument of a method that should not be null, use Object.requireXxx. The JDK designers have never advocated the use of Optional just to wrap a value and check for null. Optional is for return values.
Do new methods make Objects more preferable than Optional since they will throw NPE immediately and not later on somewhere in the code like with Optional?
See previous points: you don't use these methods to do the same thing.
The point is: those two method signatures are clearly different:
public static <T> T requireNonNullElse(T obj, T defaultObj)
vs.
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)
The javadoc for the second method reads:
Returns the first argument if it is non-null and otherwise returns the non-null value of supplier.get().
In other words: it uses the supplier that you provide to it here.
So, the answer is: you use the second version for situations where you want to work with a supplier; and otherwise you simply take the "more simple" version of that method that takes the "less complicated" parameter.
The reasoning behind that: when you decide between two options, you prefer that one that is easier/"less reader surprising" to use. In other words: why would you want to provide a supplier, when you can go without.
Regarding the usage of Optionals - keep in mind that their main goal was to be used for return types; not as method parameters (see here for further reading).
Then: updating existing methods in a class delivered "to the field" is almost always a no-go. You absolutely do not want to change the semantics of something that is already out in the open and used by your customers; assuming specific semantics.
Q. Why haven't the JDK developers updated existing methods in Optional class?
A. Because Optional class was designed to avoid NPE.
Q. Why haven't they introduced a new method (which will thrown NPE if second argument is null) to Optional class?
A. The same answer.
Q. What should we use now Optional or Objects?.
A. Both. Objects for simple "not null" checkings and Optional for chain operations like map, flatMap, `filter'.
Q. Do new methods make Objects more preferable than Optional since they will throw NPE immediately and not later on somewhere in the code like with Optional?
A. Depends on situation. If you already have Optional as return value of some method then it is preferable to use Optional.
So the main point is if you like using ifs for checking for null or not. If you have a method that can take arguments that can be of null value, It would make more sense to use Objects. The only reasonable place to use Optional is to verify a call to a method that returns optional result.
Developers wanted to use more functional way of checking for null values, so the where using the construct Optional.ofNullable for that purpose, which wasn't a good practice, because it was creating garbage.
What is the difference between plus quotes (+"") and using a "toString()" method or even explicitly casting with something like (String) myObject? Trade-offs?
myObject.toString()
vs.
myObject+""
or even vs.
(String) myObject
More specifically, is there any time using the myObj+"" method can get you into trouble?
Edited for clarity
EDIT 2:
Seems String.valueOf(myObj); is the prefered method for avoiding a null pointer. That said: Is there ever a time when the following is false?
String.valueOf(myObj).equals(myObj+"")
As of Java 7, if you want to avoid a NullPointerException, you can simply use one of these:
Objects.toString( myObject )
Objects.toString( myObject, "defaultValueWhenMyObjectIsNull" )
In all versions of Java, the first of these can also be accomplished with the following, as noted by #NobuGames in the first comment below:
String.valueOf( myObject )
The mechanisms you cite each has a flaw.
myObject.toString() // throws NullPointerException if myObject is null.
myObject+"" // Hack; impairs understandability.
(String) myObject // throws ClassCastException unless myObject is a String or null
EDIT (after question edit)
is there any time using the myObj+"" method can get you into trouble?
Yes, you can confuse other programmers. The intent of the hack is not clear. This can lead to increased cost in time, and increased risk of someone "fixing" it.
However, in terms of just the compiler, you're fine. From the Java Language Specification, section 15.18: String concatentation operator +:
If only one operand expression is of type String, then string conversion (§5.1.11) is performed on the other operand to produce a string at run time.
And from that cited section 5.1.11: String conversion:
If the reference is null, it is converted to the string "null" (four ASCII characters n, u, l, l).
Otherwise, the conversion is performed as if by an invocation of the toString method of the referenced object with no arguments; but if the result of invoking the toString method is null, then the string "null" is used instead.
This second case leads to a difference that you asked about.
Is there ever a time when the following is false? String.valueOf(myObj).equals(myObj+"")
No, but there's a time when that throws a NullPointerException. When myObj is a non-null reference to an object whose toString() method returns null, then String.valueOf(myObj) will be null. Calling the equals method will throw the NullPointerException.
But I suspect you're asking whether there's ever a time the two have different values. Yes, they can have different values. Objects.toString() and String.valueOf() can return null values. The hack will always have a non-null value.
That said, returning null from toString() is somewhat bad form. The JLS acknowledges that it can happen, but the API implies that it should not. Personally, if I were concerned about this case, I would handle it in some way other than the hack.
This code:
myObject+""
Is translated by the compiler to this:
new StringBuilder().append(myObject).append("").toString()
The StringBuilder append method does a null check on the input argument, appending the text "null".
The String class has an overloaded valueOf method, so you can also do:
String.valueOf(myObject)
Which will do a null check, returning the text "null".
Casting to String is going to be highly contextual, so more than one technique may apply here. If you are expecting to directly cast to String, my advice would be to prepare for it. If there is a chance it can be null, then check for it. Or make the API promise not to hand you a null. That is, this is a separation of concerns and a layering of responsibilities.
However, IMO, any sufficiently complicated class ought to have a toString() method. It can be for debugging, or used as a property for computation, but it ought to be human readable. There are few cases where a human-readable version of the object is not warranted, in my experience.
Relying on overloading the + operator feels like a hack, yes.
I recently saw something in some code that made me curious if it was actually having some kind of optimization or performance impact. It was a line like this in a constants file:
public static final Object NULL = null;
Then, throughout the code, rather than explicitly using the null keyword, it would be referred to with Constants.NULL.
I've seen this kind of thing before with something like:
public static final String EMPTY_STRING = "";
... and that seemed to make at least a little bit of sense, if it's an attempt to avoid creating lots of duplicate "" instances. But does it really make any difference with null, since it's not actually any kind of object? Is there something I'm missing?
Neither makes any sense. Using "" in multiple places in your code does not create multiple instances of a String object. Unless you explicitly call new String(""); the JVM just creates a pool of Strings and references the one instance of each particular String.
I don't think that defining and using NULL in this manner does more than add noise. Perhaps whoever wrote that code came from a C++ background, and preferred the more familiar look of NULL over null.
The second example is also questionable, since using "" many times would not result in a separate String object created for every use. To quote the JLS:
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.
There is a purpose to use the Object.NULL.
Suppose that you have a bunch of code that validates if your object is null or not. So as part of a new feature, you need to use default values in some cases of null object.
With the simple if obj != null you can't track down the places where you object is validates against nullity. But if you use obj != Object.NULL then you can use your IDE/editor to help you to find those usages.
Does not make any difference in memory occupied due to the string pool concept in java and also it makes the code look more dirty when using NULL constant instead of null or EMPTY_STRING instead of "".
Both of them are self explanatory so there should be no need to create a naming constant for them.
I come from a C#.net background and whenever I had a string I was declaring it as String.Empty
Now I am looking at a Java code from a co-worker and he has declared his strings in a method like this:
String myStr = null;
I don't like it, and even worse, he is assigning values to these strings in an "IF" block where it may or may not even qualify, and then at the end of the method he is calling a myStr.length() on them.
So my question is what is a preferred way in Java? do you think is it better to define them as String.Empty OR leave them as null and do a null check just before calling .length() on them?
In general, using null values is a bad idea, especially if they are returned from a method or passed to another method. Using the Null Object pattern is better, and in a string's case the Null Object is an empty string. By consistently avoiding nulls, the probability of getting a NullPointerException gets smaller and the code becomes more readable (this is discussed at length in Clean Code chapter 7, pages 110-112).
In Java String s = "" does not allocate any memory, because the JVM will have interned the string literal, so there isn't even a performance difference (and even if there were, it would be a premature optimization).
They both have their uses. Empty strings are in-band, i.e. can occur in the input, so they are no use as sentinels. Null is only useful as a sentinel. If you're going to append to it you should initialize it with "" of course. If you're going to immediately reassign it there's no need to provide any value at all, and you should probably combine the declaration with the reassignment. I see far too much of this:
String s = new String();
s = "some string";
All this tells me is that somebody doesn't understand the language.
thought both are applicable for different scenarios, assigning it null will be better(saves memory and less error prone) provided you later on set some string to that else you will be getting a null pointer exception.
An empty String is often a sign that you should either be using a StringBuilder if you're appending (which is a common case). A null reference is 'better' because it uses less memory and it's faster to check if a String is null compared to checking if it's empty. I would advice against using empty Strings instead of declaring them as null, though you should still check for null reference before you use it unless you're 100% sure that it would have been assigned a value at some stage.
What's the best practise when adapting C-style functions which return a true/false to Java?
Here's a simple method to illustrate where the problem lies.
public static boolean fileNameEndsWithExtension( String filename, String fileExtension) {
return filename.endsWith( fileExtension );
}
Note that there's probably a more elegant way of filtering files (feel free to comment on this). Anyway, if filename is a null value, does one:
Return a false if filename is null? If so, how does one go about distinguishing between the case where filename is null and the case where the String or file name doesn't end with a given file extension?
Change the return type to the wrapper class Boolean which allows a null value.
Throw an Exception and force the programmer to make sure that a null value is never passed to the method?
Use another solution?
You should throw a NullPointerException or an IllegalArgumentException if filename is null. I'll let you decide which is best. There's a good debate on which to use in the question: IllegalArgumentException or NullPointerException for a null parameter?
You do what makes sense in the problem domain of your particular application:
If it makes sense to say that the empty set of filenames ends with any extension, return true.
If it makes sense to say that the empty set of filenames ends with no extension, return false.
If it makes sense to say that no one should ever ask this question, let the code throw.
If it makes sense to have a three-values result, sure, use Boolean.
Or make a three-valued enum and return from THAT.
Most of the time, option 3 is going to be sensible, but no one here can rule out the applicability of the others to your application. If you pass a lot of meaningful null filenames around for a good reason, it might make sense to choose one of the others.
I would use either 1 or 3. Preferably I would throw NullPointerExceptions or atleast use an assert.
Returning nullable Booleans usually causes more trouble than they are worth, you have check for nulls etc. Besides fileNameEndsWithExtension() looks like a function that you'll be using only when you know that you have a valid filename.
Also do not forget that fileExtension might also be a null.
return true IFF filename.endsWith( fileExtension )
I would return false if filename is null, and not bother with the distinction between null and any other non-matching values.
If null filename is a distinct state that needs to be verified and handled specifically, then this should be validated separately, preferably before checking endsWith(), but still retain the null check in endsWith() to prevent unnecessary runtime exceptions.
The reason that I would choose the behaviour of null = false, is probably due to influence from relational databases. The following query would only return rows which match the condition, everything else (nulls and mismatches) would be ignored.
select * from filenames
where filename like '&fileExtension';