While browsing the code for the Java 8 version of ForkJoinPool(which has a few interesting changes from Java 7) I ran across this construct (here):
do {} while (!blocker.isReleasable() &&
!blocker.block());
I'm struggling with why you would write it like this instead of just
while (!blocker.isReleasable() &&
!blocker.block());
Is it just a semantics/readability choice, since you could read the first construct as do "nothing" while "conditions"? Or is there some additional benefit I'm missing?
If you read the comments at top of the file, just below the class declaration, there is a section which explains the use of this construct:
Style notes
===========
[...]
There are several occurrences of the unusual "do {} while
(!cas...)" which is the simplest way to force an update of a
CAS'ed variable. There are also other coding oddities (including
several unnecessary-looking hoisted null checks) that help
some methods perform reasonably even when interpreted (not
compiled).
ForkJoinPool makes extensive use of compareAndSwap... from sun.misc.Unsafe and most of the occurrences of do {} while (...) in ForkJoinPool can — as mentioned by other answers — be explained by this comment under the heading Style notes:
* There are several occurrences of the unusual "do {} while
* (!cas...)" which is the simplest way to force an update of a
* CAS'ed variable.
The choice to use write a while-loop with an empty body as do {} while (condition) seems however to be a mostly stylistic choice. This is perhaps clearer in HashMap, which happened to be updated in Java 8.
In the Java 7 HashMap you can find this:
while (index < t.length && (next = t[index++]) == null)
;
While much of the code around it has also changed, it is clear that the replacement in Java 8 is this:
do {} while (index < t.length && (next = t[index++]) == null);
The first version has the weakness that if the lone semicolon happened to be deleted it would change the meaning of the program depending on the following line.
As seen below, bytecode generated by while (...) {} and do {} while (...); is slightly different, but not in any way that should affect anything when run.
Java code:
class WhileTest {
boolean condition;
void waitWhile() {
while(!condition);
}
void waitDoWhile() {
do {} while(!condition);
}
}
Generated code:
class WhileTest {
boolean condition;
WhileTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
void waitWhile();
Code:
0: aload_0
1: getfield #2 // Field condition:Z
4: ifne 10
7: goto 0
10: return
void waitDoWhile();
Code:
0: aload_0
1: getfield #2 // Field condition:Z
4: ifeq 0
7: return
}
Leaving aside any potential performance benefits, there is a clear readability benefit.
With while (X) ; the trailing semicolon is not always obvious at first glance, you may be confused into thinking that the following statement or statements are inside the loop. For example:
while (x==process(y));
if (z=x) {
// do stuff.
}
It would be very easy to misread the above as having the if statement inside the loop, and even if you did read it correctly it would be easy to think that it was a programming mistake and the if should be inside the loop.
With do {} while(X); though it is immediately at a glance clear that there is no body to the loop.
If you will read comment above the code, It is mentioned that...
If the caller is not a ForkJoinTask, this method is behaviorally equivalent to
while (!blocker.isReleasable())
if (blocker.block())
return;
}
So it is just another form to implement above code in else part...!!
In Style notes it is mentioned that,
There are several occurrences of the unusual "do {} while
(!cas...)" which is the simplest way to force an update of a
CAS'ed variable.
And if you will see implementation of ManagedLocker#isReleasable, It is updating the lock and returns true if blocking is unnecessary.
Interpretation :
Blank while loops are used to provide an interrupt until some condition reset to true/false.
Here, do { } while(!...) is a blocker/interrupt until blocker.block() will be true when blocker.isReleasable() is false. Loop will continue execution while blocker is not releasable (!blocker.isReleasable()) and blocker is not blocked !! Execution will be out of loop as soon as blocker.block() will set to true.
Note that, do{ } while(...) does not update CAS variable, but it guarantee that program will wait until variable gets updated (force to wait until variable gets updated).
You can easily make something like this with:
if(true){
//Do nothing ...
}
Related
This is the code I have:
public enum Modification {
NONE, SET, REMOVE;
}
boolean foo(){
for (S s : sList) {
final Modification modification = s.getModification();
switch (modification) {
case SET:
case REMOVE:
return true;
/*
case NONE:
break;
*/
}
}
return false;
}
And when the code is as seen above, IntelliJ will say:
'for' statement does not loop less... () Reports any instance of for,
while and do statements whose bodies are guaranteed to execute at most
once. Normally, this is an indication of a bug.
Only if I make the following change, IntelliJ will be happy:
for (S s : sList) {
final Modification modification = s.getModification();
switch (modification) {
case SET:
case REMOVE:
return true;
case NONE:
break;
}
}
Why is my for loop not looping if case NONE: is not included in the switch statement?
I just tried this in eclipse and you end up with a compiler warning on the switch statement.
The enum constant NONE needs a corresponding case label in this enum switch on Modification
To resolve the warning I'm given the following options.
Add default case
Add missing case statements
Add #SuppressWarnings 'incomplete-switch' to foo()
If I add the missing case statement then the warning no longer appears. The same as adding the missing case makes your error warning disappear from intellij.
Without the statement for case NONE you can only see two cases, both of which return true. Without knowing the structure of Modification and the extra value of NONE it looks like this loop would just return true on the first iteration of the loop.
Of course the compiler should actually know that there are more values for Modification than SET and REMOVE so the warning is just for good style. Basically your code works but here's how to improve it.
I would choose to add a default statement rather than the missing case. This would be more future proof in case more values are later added to the enum. E.G.
switch (modification)
{
case SET:
case REMOVE:
return true;
default:
break;
}
Personally I'm not a fan of using the fall through on switch statements. What you gain in making the code concise you lose in legibility IMHO. If someone later comes and adds a case between SET and REMOVE it could introduce a bug. Also, having a return statement mid-way through a method can also cause problems. If someone wants to add some code just before the return they may miss all the places. If the method is very simple then multiple returns is fine but you've stated that this is a simplified example and so if this block of code is complicated I would avoid it.
If you're able to use Java 8 then this looks to be the perfect use case for the new stream API. Something like the following should work.
return sList.stream().anyMatch(
modification -> (modification==Modification.SET || modification==Modification.REMOVE)
);
i assume these are your only three cases right?, so basically its saying you are going to hit one of the first two and instantly return true, therefore not looping, just add a default case and everything should work ok, this is good practice also btw.
basically it cant see a case where it doesnt just return instantly without iterating the loop
I'd say its a false positive.
1st indication:
If you run your code through a debugger - and have elements with NONE modification in the list before an element with other modifications - it will actually loop.
2nd indication:
When you look at the generated bytecode, it transforms the switch statement to (sort of - its not exactly the same)
for (S s : sList) {
Modification modification = s.getModification();
switch (modification.ordinal()) {
case 1:
case 2:
return true;
}
}
If you put that in your code, IntelliJ does not complain.
3rd indication:
the warning dissappears if you put an additional statement before the return, i.e. System.out.println();
switch (modification) {
case SET:
case REMOVE:
System.out.println()
return true;
Seems you tricked the inspection with the missing case label and could simply ignore the warning.
I think that IntelliJ's inspections is wrong. I reported it to JetBrains
Edit : it's fixed
Your switch case always breaks or returns. In the first case, you do nothing aka it falls through. The second case returns which causes both the switch and the loop to stop. In the third case you break the switch statement which causes it to stop. It does not however stop the for loop (aka, it keeps iterating).
Either add specific functionality for the SET case or change your behaviour on the REMOVE and NONE cases.
public enum Modification {
NONE, SET, REMOVE;
}
boolean foo(){
for (S s : sList) {
final Modification modification = s.getModification();
switch (modification) {
case SET:
// This case falls through to the REMOVE case
case REMOVE:
return true; // This statement stops the switch, loop and returns true
case NONE:
break; // This statement stops the switch and continues the loop.
}
}
return false;
}
Your switch is not looping without the NONE case because return breaks the loop and returns a value from the function. break breaks the switch loop but continues the for loop.
By request of OP an extra explanation.
Falling through means the next case will be executed until a stop (break or return) is reached. This makes the following code snippets equivelant:
case SET:
case REMOVE:
return true;
is the same as:
case SET:
return true;
case REMOVE:
return true;
I have never understood what is assert used for, even though I have read plenty examples, they don't really let me know what or why should I use it for.
So Instead of asking an example, I'm gonna provide one and let me know if this is the proper usage of assert.
// The idea is that the `mode` variable should be 0 or 1, and no other number.
switch(mode) {
case 0:
// do stuff
break;
case 1:
// do other stuff
break;
default:
// assert code?
}
If this is correct, please let me know how to use it in this case. If this is not how it is supposed to use, please provide an example.
Not in this case.
If you're asserting a value, you're making a statement that, before some critical evaluation is done using this value, that it is what you assert it to be. You can assert that the value isn't null, or that it's less than 2, or something before you reach your critical code block.
assert (mode >= 0 && mode < 2); // Ensures that `mode` is between 0 and 1.
// Switch statement to follow
I would not encourage the use of that here. Your code would not read well, and unless you enable assertions with the -ea flag, your assertion would not work.
Instead, what you can do is throw an exception of some kind - if it's not 0 or 1, then the mode is an illegal value which cannot be processed, leading to exceptional/undefined behavior. Throw an exception of some kind.
switch(mode) {
case 0:
// do stuff
break;
case 1:
// do other stuff
break;
default:
throw new IllegalArgumentException("Mode is illegal");
}
assert object != null;
object.doSomething();
assert is used to verify the correctness of some precondition, invariant, or postcondition. In the example, we want to make sure object is not null when some method is called on it.
One thing to remember is that assert should never be executed in production code. We only make use of it when testing. There is a Java option to turn it on or off.
As for your specific example, you could use:
assert mode == 0;
assert mode == 1;
at the very beginning of the switch block to make sure only 0 and 1 are passed in.
P.S. The discussion on when to use assertion vs exception might help your understanding. The idea is that
Exceptions address the robustness of your application while assertions
address the correctness of your application.
Assertions are basically used to check something that should never happen.
Some assertions use cases from http://www.javapractices.com/topic/TopicAction.do?Id=102
pre-conditions (in private methods only) - the requirements which a method requires its caller to fulfill.
post-conditions - verify the promises made by a method to its caller
class invariants - validate object state
unreachable-at-runtime code - parts of your program which you expect to be unreachable, but which cannot be verified as such at compile-time (often else clauses and default cases in switch statements)
So the usage of assertion in your code is not correct
In some of our companys projects code I often read something like this:
boolean foo = Boolean.FALSE;
Besides the fact that AFAIK I only have to initialize local variables in Java at all (no random values like in Pascal) and besides the fact that especially for booleans I often WANT to have an initialization, what do I miss here? Why not:
boolean foo = false;
I don't get it. And code analyzation tools like PMD and Findbugs mark it, too. But why?
Edit:
Without really knowing much about the bytecode except that it is there I created an example class and decompiled it. The Boolean.FALSE went to:
0: getstatic #15 // Field java/lang/Boolean.FALSE:Ljava/lang/Boolean;
3: invokevirtual #21 // Method java/lang/Boolean.booleanValue:()Z
6: istore_1
The 'false' variant went to:
0: iconst_1
1: istore_1
So without knowing too much about this, I'd guess that more statements means more time to execute so it's not only wrong but also slower in the long run.
boolean foo = Boolean.FALSE;
This is strange and unnecessarily complicated code, written by someone who likely didn't know Java very well. You shouldn't write code like this, and PMD and FindBugs are right to mark this.
Boolean.FALSE is a java.lang.Boolean object that gets auto-unboxed; the compiler essentially translates this to:
boolean foo = Boolean.FALSE.booleanValue();
I don't have to initialize variables in Java at all...
Member variables do not need to be initialized explicitly; if you don't, they'll be initialized with a default value (which is false in the case of boolean). Local variables do need to be explicitly initialized; if you try to use a local variable without initializing it, the compiler will give you an error.
Both are same. but boolean foo = false; is enough.
There is no good reason to do this, it was probably just a novice Java programmer. I wouldn't worry too much, just replace it with false.
At the same time, you can usually if not always arrange your code such that you never declare a variable you don't have the final value for, i.e., making your objects immutable, which makes them easier to think about. What's the value of x? compared to What's the value of x between the calls to foo() and bar()? The first is generally easier to answer. This requires you to split up your classes along lines you might not be used to doing but I recommend at least trying it out.
The style to use an auto-unboxed Boolean constant in fact meshes well with the overall oververbosity endemic to many Java projects. For example:
public boolean isItOrIsItNotTheValueWeExpect(String aStringParameterThatCouldBeNull) {
boolean booleanReturnValue = Boolean.FALSE;
if (aStringParameterThatCouldBeNull != null) {
if (aStringParameterThatCouldBeNull.length() > 3) {
booleanReturnValue = Boolean.TRUE;
}
else {
booleanReturnValue = Boolean.FALSE;
}
}
else if (aStringParameterThatCouldBeNull == null) {
booleanReturnValue = Boolean.TRUE.booleanValue();
}
return booleanReturnValue;
}
Obviously, the code above would be much preferred to this unreadable mess:
public boolean validate(String s) {
return s == null? true : s.length() > 3;
}
The very occurrence of a ternary operator is considered a transgression and some projects even have it flagged by CheckStyle.
If your projects conform to such stylistic guidelines as these, that could justify your suspicious line of code.
There is no difference really although the 1st method won't work on a 1.4 or earlier JVM. The first is more convoluted since it is fetching the static value from the Boolean object and then relying on autoboxing (introduced in 1.5) to change it from a Boolean object to a boolean primitive) although I can't imagine it would ever make any speed difference.
Generally though if you are assuming a particular initial value for a variable then I would recommend initialising it rather than just declaring it as it makes the code more readable.
I am replacing a old C++ code with Java:I know there is no equivalent of goto in java as it causes many surprising errors and unintended loop terminations.
C++ code: //I have skipped the actual code
for(//some condition){
if (excl(grds[i],0))
{
//do something
goto breakout;
}
//some more code
breakout:
//rest of the code
}//end of for loop
Java representation:
for(//some condition){
if (excl(grds[i],0))
{
//do something
}
else
{
//some more code
}
//rest of the code
}//end of for loop
I have kept the "some more code" part in the else section so I guess it will function same as the breakout. When the if condition is true it wont go to the else part and rest of the code will be executed as usual. I guess break or continue wont serve the purpose as we need to any way run the rest of the code section for all iterations.
Is this the correct way of representing this C++ code in Java?
Yes, that would be the better way — in Java, and in C++.
This is probably the easiest way:
for(//some condition){
if(!excl(grds[i],0))
{
//some more code
}
//rest of the code
}//end of for loop
You really shouldn't be using goto in C++. As a side note, in Java you can have named blocks that can be used to simulate a goto:
namedBlock:
{
// some code
if(condition)
break namedBlock;
// some more code
}
// rest of the code
But this is awful practice. Don't do it. Forget I even mentioned it ;)
for(//some condition){
if (!(excl(grds[i],0)))
{
//some more code
}
//rest of the code
}//end of for loop
Edit: after your clarification, the way you did it is fine.
Why can't you have it like this?
In your C++ code, //some more code is only executed when the condition is false and the //rest is always executed. So put that in the if.
Yes.
To be more precise, that's the correct best way of representing that code in C++ as well. Why use goto instead of a simple if?
This is a hack
for(//some condition){
do { // note this *do*
if (excl(grds[i],0))
{
break; // out of do/while
}
//some more code
}
while(false); // do only once
//rest of the code
}//end of for loop
I'm sure people will hate me for this, but you can get closer to the goto statement in Java than the if/else example. For instance, you can do:
for(/*some condition*/){
breakout: {
if (excl(grds[i],0)) {
break breakout; //this will jump to the end of the "breakout" block
}
//some more code
}
//rest of the code
}
Of course, this is not an example of good Java coding style, and just because this can be done doesn't mean it should be done. Really you should stick with the if/else.
There are occasions, very rare occasions, when using goto is exactly the right choice in C++. The example shown is not one of them. This is a goto that should never have been used, period. A goto has zero reason for existence if you can eliminate the goto with no additional variables, no increase in the complexity.
Some valid uses of goto in C++ can be easily eliminated in Java.
C and C++ do not have a way to break or continue out of a nested loop. Java does. When the target of a goto is immediately before some close brace, change the goto label with continue label. When the target of a goto is immediately after some close brace, change the goto label with break label. (The label statement may need to be moved around.)
Some C++ code uses goto in lieu of throw for local error handling / local error recovery. C++ exceptions have a pretty stiff performance penalty. If the code is being converting to Java it's kinda obvious that performance is not an issue. Use Java exceptions for this kind of goto.
There are some patterns for checking whether a parameter to a method has been given a null value.
First, the classic one. It is common in self-made code and obvious to understand.
public void method1(String arg) {
if (arg == null) {
throw new NullPointerException("arg");
}
}
Second, you can use an existing framework. That code looks a little nicer because it only occupies a single line. The downside is that it potentially calls another method, which might make the code run a little slower, depending on the compiler.
public void method2(String arg) {
Assert.notNull(arg, "arg");
}
Third, you can try to call a method without side effects on the object. This may look odd at first, but it has fewer tokens than the above versions.
public void method3(String arg) {
arg.getClass();
}
I haven't seen the third pattern in wide use, and it feels almost as if I had invented it myself. I like it for its shortness, and because the compiler has a good chance of optimizing it away completely or converting it into a single machine instruction. I also compile my code with line number information, so if a NullPointerException is thrown, I can trace it back to the exact variable, since I have only one such check per line.
Which check do you prefer, and why?
Approach #3: arg.getClass(); is clever, but unless this idiom see widespread adoption, I'd prefer the clearer, more verbose methods as opposed to saving a few characters. I'm a "write once, read many" kind of programmer.
The other approaches are self-documenting: there's a log message you can use to clarify what happened - this log message is use when reading the code and also at run-time. arg.getClass(), as it stands, is not self-documenting. You could use a comment at least o clarify to reviewers of the code:
arg.getClass(); // null check
But you still don't get a chance to put a specific message in the runtime like you can with the other methods.
Approach #1 vs #2 (null-check+NPE/IAE vs assert): I try to follow guidelines like this:
http://data.opengeo.org/GEOT-290810-1755-708.pdf
Use assert to check parameters on private methods
assert param > 0;
Use null check + IllegalArgumentException to check parameters on public methods
if (param == null) throw new IllegalArgumentException("param cannot be null");
Use null check + NullPointerException where needed
if (getChild() == null) throw new NullPointerException("node must have children");
HOWEVER, since this is question may be about catching potential null issues most efficiently, then I have to mention my preferred method for dealing with null is using static analysis, e.g. type annotations (e.g. #NonNull) a la JSR-305. My favorite tool for checking them is:
The Checker Framework:
Custom pluggable types for Java
https://checkerframework.org/manual/#checker-guarantees
If its my project (e.g. not a library with a public API) and if I can use the Checker Framework throughout:
I can document my intention more clearly in the API (e.g. this parameter may not be null (the default), but this one may be null (#Nullable; the method may return null; etc). This annotation is right at the declaration, rather than further away in the Javadoc, so is much more likely to be maintained.
static analysis is more efficient than any runtime check
static analysis will flag potential logic flaws in advance (e.g. that I tried to pass a variable that may be null to a method that only accepts a non-null parameter) rather than depending on the issue occurring at runtime.
One other bonus is that the tool lets me put the annotations in a comment (e.g. `/#Nullable/), so my library code can compatible with type-annotated projects and non-type-annotated projects (not that I have any of these).
In case the link goes dead again, here's the section from GeoTools Developer Guide:
http://data.opengeo.org/GEOT-290810-1755-708.pdf
5.1.7 Use of Assertions, IllegalArgumentException and NPE
The Java language has for a couple of years now made an assert keyword available; this keyword can be used to perform debug only checks.
While there are several uses of this facility, a common one is to check method parameters on private (not public) methods. Other uses are
post-conditions and invariants.
Reference: Programming With Assertions
Pre-conditions (like argument checks in private methods) are typically easy targets for assertions. Post-conditions and invariants are sometime
less straighforward but more valuable, since non-trivial conditions have more risks to be broken.
Example 1: After a map projection in the referencing module, an assertion performs the inverse map projection and checks the result
with the original point (post-condition).
Example 2: In DirectPosition.equals(Object) implementations, if the result is true, then the assertion ensures that
hashCode() are identical as required by the Object contract.
Use Assert to check Parameters on Private methods
private double scale( int scaleDenominator ){
assert scaleDenominator > 0;
return 1 / (double) scaleDenominator;
}
You can enable assertions with the following command line parameter:
java -ea MyApp
You can turn only GeoTools assertions with the following command line parameter:
java -ea:org.geotools MyApp
You can disable assertions for a specific package as shown here:
java -ea:org.geotools -da:org.geotools.referencing MyApp
Use IllegalArgumentExceptions to check Parameters on Public Methods
The use of asserts on public methods is strictly discouraged; because the mistake being reported has been made in client code - be honest and
tell them up front with an IllegalArgumentException when they have screwed up.
public double toScale( int scaleDenominator ){
if( scaleDenominator > 0 ){
throw new IllegalArgumentException( "scaleDenominator must be greater than 0");
}
return 1 / (double) scaleDenominator;
}
Use NullPointerException where needed
If possible perform your own null checks; throwing a IllegalArgumentException or NullPointerException with detailed information
about what has gone wrong.
public double toScale( Integer scaleDenominator ){
if( scaleDenominator == null ){
throw new NullPointerException( "scaleDenominator must be provided");
}
if( scaleDenominator > 0 ){
throw new IllegalArgumentException( "scaleDenominator must be greater than 0");
}
return 1 / (double) scaleDenominator;
}
Aren't you optimizing a biiiiiiiiiiiiiiit too prematurely!?
I would just use the first. It's clear and concise.
I rarely work with Java, but I assume there's a way to have Assert only operate on debug builds, so that would be a no-no.
The third gives me the creeps, and I think I would immediately resort to violence if I ever saw it in code. It's completely unclear what it's doing.
You can use the Objects Utility Class.
public void method1(String arg) {
Objects.requireNonNull(arg);
}
see http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#requireNonNull%28T%29
You should not be throwing NullPointerException. If you want a NullPointerException, just dont check the value and it will be thrown automatically when the parameter is null and you attempt to dereference it.
Check out the apache commons lang Validate and StringUtils classes.
Validate.notNull(variable) it will throw an IllegalArgumentException if "variable" is null.
Validate.notEmpty(variable) will throw an IllegalArgumentException if "variable" is empty (null or zero length".
Perhaps even better:
String trimmedValue = StringUtils.trimToEmpty(variable) will guarantee that "trimmedValue" is never null. If "variable" is null, "trimmedValue" will be the empty string ("").
In my opinion, there are three issues with the third method:
The intent is unclear to the casual reader.
Even though you have line number information, line numbers change. In a real production system, knowing that there was a problem in SomeClass at line 100 doesn't give you all the info you need. You also need to know the revision of the file in question and be able to get to that revision. All in all, a lot of hassle for what appears to be very little benefit.
It is not at all clear why you think the call to arg.getClass can be optimized away. It is a native method. Unless HotSpot is coded to have specific knowledge of the method for this exact eventuality, it'll probably leave the call alone since it can't know about any potential side-effects of the C code that gets called.
My preference is to use #1 whenever I feel there's a need for a null check. Having the variable name in the error message is great for quickly figuring out what exactly has gone wrong.
P.S. I don't think that optimizing the number of tokens in the source file is a very useful criterion.
The first method is my preference because it conveys the most intent. There are often shortcuts that can be taken in programming but my view is that shorter code is not always better code.
x==null is super fast, and it can be a couple of CPU clocks (incl. the branch prediction which is going to succeed). AssertNotNull will be inlined, so no difference there.
x.getClass() should not be faster than x==null even if it uses trap. (reason: the x will be in some register and checking a register vs an immediate value is fast, the branch is going to be predicted properly as well)
Bottom line: unless you do something truly weird, it'd be optimized by the JVM.
The first option is the easiest one and also is the most clear.
It's not common in Java, but in C and C++ where the = operator can be included in a expression in the if statement and therefore lead to errors, it's often recommended to switch places between the variable and the constant like this:
if (NULL == variable) {
...
}
instead of:
if (variable == NULL) {
...
}
preventing errors of the type:
if (variable = NULL) { // Assignment!
...
}
If you make the change, the compiler will find that kind of errors for you.
While I agree with the general consensus of preferring to avoid the getClass() hack, it is worth noting that, as of OpenJDK version 1.8.0_121, javac will use the getClass() hack to insert null checks prior to creating lambda expressions. For example, consider:
public class NullCheck {
public static void main(String[] args) {
Object o = null;
Runnable r = o::hashCode;
}
}
After compiling this with javac, you can use javap to see the bytecode by running javap -c NullCheck. The output is (in part):
Compiled from "NullCheck.java"
public class NullCheck {
public NullCheck();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: aconst_null
1: astore_1
2: aload_1
3: dup
4: invokevirtual #2 // Method java/lang/Object.getClass:()Ljava/lang/Class;
7: pop
8: invokedynamic #3, 0 // InvokeDynamic #0:run:(Ljava/lang/Object;)Ljava/lang/Runnable;
13: astore_2
14: return
}
The instruction set at "lines" 3, 4 and 7 are basically invoking o.getClass(), and discarding the result. If you run NullCheck, you'll get a NullPointerException thrown from line 4.
Whether this is something that the Java folks concluded was a necessary optimization, or it is just a cheap hack, I don't know. However, based on John Rose's comment at https://bugs.openjdk.java.net/browse/JDK-8042127?focusedCommentId=13612451&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13612451, I suspect that it may indeed be the case that the getClass() hack, which produces an implicit null check, may be ever so slightly more performant than its explicit counterpart. That said, I would avoid using it unless careful benchmarking showed that it made any appreciable difference.
(Interestingly, the Eclipse Compiler For Java (ECJ) does not include this null check, and running NullCheck as compiled by ECJ will not throw a n NPE.)
I'd use the built-in Java assert mechanism.
assert arg != null;
The advantage of this over all the other methods is that it can be switched off.
I prefer method 4, 5 or 6, with #4 being applied to public API methods and 5 / 6 for internal methods, although #6 would be more frequently applied to public methods.
/**
* Method 4.
* #param arg A String that should have some method called upon it. Will be ignored if
* null, empty or whitespace only.
*/
public void method4(String arg) {
// commons stringutils
if (StringUtils.isNotBlank(arg) {
arg.trim();
}
}
/**
* Method 5.
* #param arg A String that should have some method called upon it. Shouldn't be null.
*/
public void method5(String arg) {
// Let NPE sort 'em out.
arg.trim();
}
/**
* Method 6.
* #param arg A String that should have some method called upon it. Shouldn't be null.
*/
public void method5(String arg) {
// use asserts, expect asserts to be enabled during dev-time, so that developers
// that refuse to read the documentations get slapped on the wrist for still passing
// null. Assert is a no-op if the -ae param is not passed to the jvm, so 0 overhead.
assert arg != null : "Arg cannot be null"; // insert insult here.
arg.trim();
}
The best solution to handle nulls is to not use nulls. Wrap third-party or library methods that may return nulls with null guards, replacing the value with something that makes sense (such as an empty string) but does nothing when used. Throw NPE's if a null really shouldn't be passed, especially in setter methods where the passed object doesn't get called right away.
There is no vote for this one, but I use a slight variation of #2, like
erStr += nullCheck (varName, String errMsg); // returns formatted error message
Rationale: (1) I can loop over a bunch of arguments, (2) The nullCheck method is tucked away in a superclass and (3) at the end of the loop,
if (erStr.length() > 0)
// Send out complete error message to client
else
// do stuff with variables
In the superclass method, your #3 looks nice, but I wouldn't throw an exception (what is the point, somebody has to handle it, and as a servlet container, tomcat will ignore it, so it might as well be this())
Regards, - M.S.
First method. I would never do the second or the third method, not unless they are implemented efficiently by the underlying JVM. Otherwise, those two are just prime examples of premature optimization (with the third having a possible performance penalty - you don't want to be dealing and accessing class meta-data in general access points.)
The problem with NPEs is that they are things that cross-cut many aspects of programming (and my aspects, I mean something deeper and more profound that AOP). It is a language design problem (not saying that the language is bad, but that it is one fundamental short-coming... of any language that allows null pointers or references.)
As such, it is best to simply deal with it explicitly as in the first method. All other methods are (failed) attempts to simplify a model of operations, an unavoidable complexity that exists on the underlying programming model.
It is a bullet that we cannot avoid to bite. Deal with it explicitly as it is - in the general case that is - the less painful down the road.
I believe that the fourth and the most useful pattern is to do nothing. Your code will throw NullPointerException or other exception a couple of lines later (if null is illegal value) and will work fine if null is OK in this context.
I believe that you should perform null check only if you have something to do with it. Checking to throw exception is irrelevant in most cases.
Just do not forget to mention in javadoc whether the parameter can be null.