Is the presence/absence of #SafeVarargs annotation really a useful distinction? - java

This question is not about how heap pollution can occur. This question is not about what effect the annotation #SafeVarargs has. I understand that it is used to suppress warnings, both locally and at call sites. I read the documentation. My question is: why was this annotation added to the Java language at all?
Consider the following:
The absence of the annotation is not a useful distinction. There is never a situation where you could intend to use the VarArgs in an unsafe way, i.e. "UnsafeVarargs".
This differs from other annotations like #Override where the absence of the annotation is a useful distinction: "hey I don't intend to override any method in my superclass, warn me if somebody adds a method with the same signature to my superclass."
Either the programmers know how to use Varargs safely or they do not. If they add the annotation it does not change that. So isn't it just providing a false sense of security for callers?
This reminds me of the flawed notion that holding your car door handle up while closing the door will prevent you from locking your keys inside.
Continuing from point 2, wouldn't it be better to disable the warning globally by default, and then re-enable it globally when doing an extensive review?
Maybe I am missing something. Maybe the annotation plays a useful role when migrating from old versions of Java? I welcome your answers. Thanks.

Continuing from point 2, wouldn't it be better to disable the warning globally by default, and then re-enable it globally when doing an extensive review?
That sounds like a really bad thing for reality.
In reality, you strive for a zero tolerance policy. Zero waste in your code, zero warnings, zero errors, zero unit test fails. And you keep checking your "counts" all the time. You add 5 lines of code to your class; and that class gets an yellow ! (eclipse telling you about warnings in there) ... you go in and fix them - immediately. And not at some hypothetical future point in time when somebody happens to enable warnings globally.
In other words: you never ever even consider to disable warnings globally.
So, the other way round: there are occasions when the compiler can only detect: "there might be a problem" - and then the compiler better warns about that. But for situations where the programmer can reasonable assess the situation, such annotations are a simple, straight forward mean (working on really local scope!) to suppress that compiler warning.
But you are certainly correct in your assumption that a programmer who doesn't understand varargs might inadvertently use that annotation in an incorrect manner, too. A reasonable strategy to address could be: "have code reviews focus on code that uses this annotation" for example. Instead of globally disabling warnings.

Related

When is it appropriate to annotate something as #NotNull in Java?

This is my first question on here and I'm pretty new to Java, so please pardon me if this is kind of a silly question.
I am working on "documenting" the expected behavior of my application from within using JavaDocs and annotations, but I'm just curious if it's appropriate or good practice to use #NotNull on a method that SHOULDN'T ever return null, but may due to future developer error.
Thanks.
This really depends on what tooling you're using. The #NotNull annotation doesn't actually do anything. Actually, there are several different #NotNull annotations provided by different libraries. None of them do anything on their own, other than signalling the programmer's intent.
To make the annotation do anything, you need to combine it with a tool that will process the annotation (either at compile time or at run time) and apply some validation to your code or your data. For example:
IntelliJ IDEA contains tools which will check that your code abides by the nullability annotations you've included.
Bean validation can be used at runtime to check, for example, that user input doesn't violate the nullability constraints.
Even without the tooling, I would say that yes, these annotations can be useful to signal intent. You can always remove the annotation if it becomes untrue.
It sounds like it would be a good idea in your case for all contributors to the codebase to use a tool, like IntelliJ IDEA, that will check for compliance with these annotations at compile time. That will help you to avoid the type of developer error that you describe.
As far as I'm aware, there is not enforced standard globally to use these types of annotations. It makes sense to use them when writing a public API, but this is project specific.
In any case, feel free to do so in your project if it would help with code clarity and readability.
It's not an anti-pattern to have javadocs with annotations.
Also, if you are considering of warning the user of your method that it shouldn't return a null, but there is a chance of that happening (since you cannot enforce it), you might want to look into the Optional class.
yes it is good practice to use #NotNull. The #NotNull Annotation is, actually, an explicit contract declaring the following:
A method should not return null.
A variable (like fields, local variables, and parameters)cannot hold a null value.
So to keep it simple, it is a good practice.

Advantage of #SuppressWarnings annotation

#SuppressWarnings annotation is for cleaner code or by adding it is there any performance gain or any advantage ?
or can we reduce compile time by doing so.
The #SuppressWarnings annotation type allows Java programmers to disable compilation warnings for a certain part of a program (type, field, method, parameter, constructor, and local variable). Normally warnings are good. However in some cases they would be inappropriate and annoying. So programmers can choose to tell the compiler ignoring such warnings if needed.
There is no relation with performance.
The developer who wrote the code knew that it was always going to be safe, decided to use #SuppressWarnings("unchecked") to suppress the warning at compilation.
As mentioned by others, it is just a trust between the developer and code written.
more info here and here
There is no performance gain, only when compiling, compiler will or will not write a waring. However after compilation, there is no difference whatsoever.
It does not make your code cleaner or improve the performance. It just helps you to concentrate your attention on potentially dangerous code. If you have a list of 130 warnings you will soon stop to read them.
Most warnings represents bad programming practices or potencial problems that the compiler is not able to solve. A finished program should, ideally, compile with no warnings. This way, when you modify it and a new warning appears you can decide what to do.
For example:
Unreachable code. What was I thinking here
Lib ZZZ is deprecated. Should I upgrade to the new one? Can I continue with this for now?
Add type arguments to list... ups, I should be using generics
SuppressWarnings annotation is just to suppress warnings that you know are sure to occur and you don't care about it. Its just helps you to have a cleaner inspection, suppressing warnings you expect to see. No performance gain.

Should the RequireThis check in Checkstyle be enabled?

One of the built-in Checkstyle checks is RequireThis, which will go off whenever you don't prepend this. to local field or method invocations. For example,
public final class ExampleClass {
public String getMeSomething() {
return "Something";
}
public String getMeSomethingElse() {
//will violate Checkstyle; should be this.getMeSomething()
return getMeSomething() + " else";
}
}
I'm struggling with whether this check is justified. In the above example, the ExampleClass is final, which should guarantee that the "right" version of getMeSomething should be invoked. Additionally, there seem to be instances where you might want subclasses to override default behavior, in which case requiring "this" is the wrong behavior.
Finally, it seems like overly defensive coding behavior that only clutters up the source and makes it more difficult to see what is actually going on.
So before I suggest to my architect that this is a bad check to enable, I'm wondering if anyone else has enabled this check? Have you caught a critical bug as a result of a missing this?
The RequireThis rule does have a valid use in that it can prevent a possible bug in methods and constructors when it applies to fields. The code below is almost certainly a bug:
void setSomething(String something) {
something = something;
}
Code like this will compile but will do nothing except reassign the value of the method parameter to itself. It is more likely that the author intended to do this:
void setSomething(String something) {
this.something = something;
}
This is a typo that could happen and is worth checking for as it may help to prevent hard to debug problems if the code fails because this.something is not set much later in the program.
The checkstyle settings allow you to keep this useful check for fields while omitting the largely unnecessary check for methods by configuring the rule like this:
<module name="RequireThis">
<property name="checkMethods" value="false"/>
</module>
When it comes to methods this rule has no real effect because calling this.getMeSomething() or just getMeSomething() has no effect on Java's method resolution. Calling this.getSomethingStatic() still works when the method is static this is not an error, it is only a warning in various IDEs and static analysis tools.
I would definitely turn it off. Using this.foo() is non-idiomatic Java, and should therefore only be used when necessary, to signal that something special is going on in the code. For example, in a setter:
void setFoo(int foo) {this.foo = foo;}
When I read code that makes gratuitous use of this, I generally mark it up to a programmer without a firm grasp on object-oriented programming. Largely because I have generally seen that style of code from programmers that don't understand that this isn't required everywhere.
I'm frankly surprised to see this as a rule in CheckStyle's library.
Calling with "this." does not stop the invocation from calling an overridden method in a subclass, since this refers to "this object" not "this class". It should stop you from mistaking a static method for an instance method though.
To be honest, that doesn't sound like a particularly common problem, I personally wouldn't think it was worth the trade-off.
Personally I wouldn't enable it. Mostly because whenever I read code I read it in an IDE (or something else that does smart code formatting). This means that the different kind of method calls and field accesses are formatted based on their actual semantic meaning and not based on some (possibly wrong) indication.
this. is not necessary for the compiler and when the IDE does smart formatting, then it's not necessary for the user either. And writing unnecessary code is just a source of errors in this code (in this example: using this. in some places and not using it in other places).
I would enable this check only for fields, because I like the extra information added by 'this.' in front of a field.
See my (old) question: Do you prefix your instance variable with ‘this’ in java ?.
But for any other project, especially legacy ones, I would not activate it:
chances are, the keyword 'this.' is almost never used, meaning this check would generate tons of warnings.
naming overrides (like a field and a method with a similar name) are very rare due to the current IDE flagging by default that code with a warning of their own.

Some (anti-)patterns on using assert (Java, and others)

Finally, I have a question to ask on Stack Overflow! :-)
The main target is for Java but I believe it is mostly language agnostic: if you don't have native assert, you can always simulate it.
I work for a company selling a suite of softwares written in Java. The code is old, dating back to Java 1.3 at least, and at some places, it shows... That's a large code base, some 2 millions of lines, so we can't refactor it all at once.
Recently, we switched the latest versions from Java 1.4 syntax and JVM to Java 1.6, making conservative use of some new features like assert (we used to use a DEBUG.ASSERT macro -- I know assert has been introduced in 1.4 but we didn't used it before), generics (only typed collections), foreach loop, enums, etc.
I am still a bit green about the use of assert, although I have read a couple of articles on the topic. Yet, some usages I see leave me perplex, hurting my common sense... ^_^ So I thought I should ask some questions, to see if I am right to want to correct stuff, or if it goes against common practices. I am wordy, so I bolded the questions, for those liking to skim stuff.
For reference, I have searched assert java in SO and found some interesting threads, but apparently no exact duplicate.
How to avoid “!= null” statements in java? and How much null checking is enough? are quite relevant, because lot of asserts we have just check if variable is null. At some places in our code, there are usages of the null object (eg. returning new String[0]) but not always. We have to live with that, at least for maintenance of legacy code.
Some good answers also in Java assertions underused.
Oh, and SO indicates with reason that When should I use Debug.Assert()? question is related too (nice feature to reduce duplicates!).
First, main issue, which triggered my question today:
SubDocument aSubDoc = documents.GetAt( i );
assert( aSubDoc != null );
if ( aSubDoc.GetType() == GIS_DOC )
{
continue;
}
assert( aSubDoc.GetDoc() != null );
ContentsInfo ci = (ContentsInfo) aSubDoc.GetDoc();
(Yes, we use MS' C/C++ style/code conventions. And I even like it (coming from same background)! So sue us.)
First, the assert() form comes from conversion of DEBUG.ASSERT() calls. I dislike the extra parentheses, since assert is a language construct, not (no longer, here) a function call. I dislike also return (foo); :-)
Next, the asserts don't test here for invariants, they are rather used as guards against bad values. But as I understand it, they are useless here: the assert will throw an exception, not even documented with a companion string, and only if assertions are enabled. So if we have -ea option, we just have an assertion thrown instead of the regular NullPointerException one. That doesn't look like a paramount advantage, since we catch unchecked exceptions at highest level anyway.
Am I right supposing we can get rid of them and live with that (ie. let Java raise such unckecked exception)? (or, of course, test against null value if likely, which is done in other places).
Side note: should I have to assert in the above snippet, I would do that against ci value, not against the getter: even if most getters are optimized/inlined, we cannot be sure, so we should avoid calling it twice.
Somebody told, in the last referenced thread, that public methods should use tests against values of parameters (usage of the public API) and private methods should rely on asserts instead. Good advice.
Now, both kinds of methods must check another source of data: external input. Ie. data coming from user, from a database, from some file or from the network, for example.
In our code, I see asserts against these values. I always change these to real test, so they act even with assertions disabled: these are not invariants and must be properly handled.
I see only one possible exception, where input is supposed constant, for example a database table filled with constants used in relations: program would break if this table is changed but corresponding code wasn't updated.
Do you see other exceptions?
Another relatively frequent use I see, which seems OK: in the default of a switch, or at the end of a series of else if testing all possible values (these cases date back before our use of enums!), there is often an assert false : "Unexpected value for stuff: " + stuff;
Looks legitimate for me (these cases shouldn't happen in production), what do you think? (beyond the "no switch, use OO" advices which are irrelevant here).
And finally, are there any other useful use cases or annoying gotchas I missed here? (probably!)
The number one rule is to avoid side-effects in assertions. In other words, the code should behave identically with assertions turned off as it does when assertions are turned on and not failing (obviously assertions that fail are going to alter the behaviour because they will raise an error).
The number two rule is not to use assertions for essential checks. They can be turned off (or, more correctly, not turned on). For parameter-checking of non-private methods use IllegalArgumentException.
Assertions are executable assumptions. I use assertions to state my beliefs about the current state of the program. For example, things like "I assume that n is positive here", or "I assume that the list has precisely one element here".
I use assert, not only for parameter validation, but also used for verifying Threads.
Every time I do swing, I write assert in almost every method to mark "I should only be execute in worker thread/AWTThread". (I think Sun should do it for us.) Because of the Swing threading model, it MAY NOT fail (and randomly fail) if you access swing api from non-UI thread. It is quite difficult to find out all these problem without assert.
Another example I can imagination is to check JAR enclosed resource. You can have english exception rather then NPE.
EDIT:
Another example; object lock checking. If I know that I am going to use nested synchronized block, or when I am going to fix a deadlock, I use Thread.holdLock(Object) to ensure I won't get the locks in reverse order.
EDIT(2): If you are quite sure some code block should never be reach, you may write
throw new AssertionError("You dead");
rather then
assert false:"I am lucky";
For example, if you override "equals(Object)" on a mutable object, override hashCode() with AssertionError if you believe it will never be the key. This practice is suggested in some books. I won't hurt performance (as it should never reach).
you have touched on many of the reasons why i think asserts should be avoided in general. unless you are working with a codebase where assert usage has very strict guidelines, you very quickly get into a situation where you cannot ever turn the assertions off, in which case you might as well just be using normal logic tests.
so, my recommendation is skip the assertions. don't stick in extra null-pointer checks where the language will do it for you. however, if the pointer may not be dereferenced for a while, up-front null checking is a good idea. also, always use real exceptions for cases which should "never" happen (the final if branch or the default switch case), don't use "assert false". if you use an assertion, there's a chance someone could turn it off, and if the situation actually happens, things will get really confused.
I recommend checking parameters in public (API) methods and throwing IllegalArgumentException if the params aren't valid. No asserts here as an API user requires to get a proper error (message).
Asserts should be used in non-public methods to check post-conditions and possibly pre-conditions. For example:
List returnListOfSize(int size) {
// complex list creation
assert list.size == size;
}
Often using a clever error handling strategy asserts can be circumvented.

Java assertions underused

I'm wondering why the assert keyword is so underused in Java? I've almost never seen them used, but I think they're a great idea. I certainly much prefer the brevity of:
assert param != null : "Param cannot be null";
to the verbosity of:
if (param == null) {
throw new IllegalArgumentException("Param cannot be null");
}
My suspicion is that they're underused because
They arrived relatively late (Java 1.4), by which time many people had already established their Java programming style/habit
They are turned off at runtime by default
assertions are, in theory, for testing invariants, assumptions that must be true in order for the code to complete properly.
The example shown is testing for valid input, which isn't a typical usage for an assertion because it is, generally, user supplied.
Assertions aren't generally used in production code because there is an overhead and it is assumed that situations where the invariants fail have been caught as coding errors during development and testing.
Your point about them coming "late" to java is also a reason why they aren't more widely seen.
Also, unit testing frameworks allow for some of the need for programmatic assertions to be external to the code being tested.
It's an abuse of assertions to use them to test user input. Throwing an IllegalArgumentException on invalid input is more correct, as it allows the calling method to catch the exception, display the error, and do whatever it needs to (ask for input again, quit, whatever).
If that method is a private method inside one of your classes, the assertion is fine, because you are just trying to make sure you aren't accidentally passing it a null argument. You test with assertions on, and when you have tested all the paths through and not triggered the assertion, you can turn them off so that you aren't wasting resources on them. They are also useful just as comments. An assert at the start of a method is good documentation to maintainers that they should be following certain preconditions, and an assert at the end with a postcondition documents what the method should be doing. They can be just as useful as comments; moreso, because with assertions on, they actually TEST what they document.
Assertions are for testing/debugging, not error-checking, which is why they are off by default: to discourage people from using assertions to validate user input.
In "Effective Java", Joshua Bloch suggested (in the "Check parameters for validity" topic) that (sort of like a simple rule to adopt), for public methods, we shall validate the arguments and throw a necessary exception if found invalid, and for non-public methods (which are not exposed and you as the user of them should ensure their validity), we can use assertions instead.
From Programming with Assertions
By default, assertions are disabled at runtime. Two command-line switches allow you to selectively enable or disable assertions.
This means that if you don't have complete control over the run-time environment, you can't guarantee that the assertion code will even be called. Assertions are meant to be used in a test-environment, not for production code. You can't replace exception handling with assertions because if the user runs your application with assertions disabled (the default), all of your error handling code disappears.
#Don, you are frustrated that assertion are turned off by default. I was also, and thus wrote this little javac plugin that inlines them (ie emits the bytecode for if (!expr) throw Ex rather than this silly assert bytecode.
If you include fa.jar in your classpath while compiling Java code, it will do its magic and then tell
Note: %n assertions inlined.
#see http://smallwiki.unibe.ch/adriankuhn/javacompiler/forceassertions and alternatively on github https://github.com/akuhn/javac
I'm not sure why you would bother to write asserts and then replace them with a standard if then condition statement, why not just write the conditions as ifs in the first place?
Asserts are for testing only, and they have two side effects: Larger binaries and degraded performance when enabled (which is why you can turn them off!)
Asserts shouldn't be used to validate conditions because that means the behaviour of your app is different at run time when asserts are enabled/disabled - which is a nightmare!
Assertions are useful because they:
catch PROGRAMMING errors early
document code using code
Think of them as code self-validation. If they fail it should mean that your program is broken and must stop. Always turn them on while unit testing !
In The Pragmatic Programmer they even recommend to let them run in production.
Leave Assertions Turned On
Use Assertions to Prevent the Impossible.
Note that assertions throw AssertionError if they fail, so not caught by catch Exception.
tl;dr
Yes, use assertion-testing in production where it makes sense.
Use other libraries (JUnit, AssertJ, Hamcrest, etc.) rather than the built-in assert facility if you wish.
Most of the other Answers on this page push the maxim "Assertions aren't generally used in production code”. While true in productivity apps such as a word-processor or spreadsheet, in custom business apps where Java is so commonly used, assertion-testing in production is extremely useful, and common.
Like many maxims in the world of programming, what starts out true in one context is misconstrued and then misapplied in other contexts.
Productivity Apps
This maxim of "Assertions aren't generally used in production code”, though common, is incorrect.
Formalized assertion-testing originated with apps such as a word-processor like Microsoft Word or a spreadsheet like Microsoft Excel. These apps might invoke an array of assertion tests assertions on every keystroke made by the user. Such extreme repetition impacted performance severely. So only the beta-versions of such products in limited distribution had assertions enabled. Thus the maxim.
Business Apps
In contrast, in business-oriented apps for data-entry, database, or other data-processing, the use of assertion-testing in production is enormously useful. The insignificant hit on performance makes it quite practical – and common.
Test business rules
Verifying your business rules at runtime in production is entirely reasonable, and should be encouraged. For example:
If an invoice must have one or more line items at all times, then write an assertion testing than the count of invoice line items is greater than zero.
If a product name must be at least 3 characters or more, write an assertion testing the length of the string.
When calculating the balance for a cash ledger, you know the result can never be negative, so run a check for a negative number signaling a flaw in the data or code.
Such tests have no significant impact on performance in production.
Runtime conditions
If your app expects certain conditions to always be true when your app runs in production, write those expectations into your code as assertion tests.
If you expect those conditions may reasonably on occasion fail, then do not write assertion tests. Perhaps throw certain exceptions. Then try to recover where possible.
Sanity-checks
Sanity checks at runtime in production is also entirely reasonable, and should be encouraged. Testing a few arbitrary conditions that one could not imagine being untrue has saved my bacon in countless situations when some bizarre happening occurred.
For example, testing that rounding a nickel (0.05) to the penny resulted in a nickel (0.05) in a certain library helped me in being one of the first people to discover a floating-point technology flaw that Apple shipped in their Rosetta library during the PowerPC-to-Intel transition. Such a flaw reaching the public would have seemed impossible. But amazingly, the flaw had escaped the notice of the originating vendor, Transitive, and Apple, and the early-access developers testing on Apple’s betas.
(By the way, I should mention… never use floating-point for money, use BigDecimal.)
Choice of frameworks
Rather than use the built-in assert facility, you may want to consider using another assertion framework. You have multiple options, including:
JUnitSee: org.junit.jupiter.api.Assertions.
AssertJKnown for its slick fluent interface.
HamcrestUsed across many languages (Java, Python, Ruby, Swift, etc.).
Or roll-your-own. Make a little class to use in your project. Something like this.
package work.basil.example;
public class Assertions {
static public void assertTrue ( Boolean booleanExpression , CharSequence message ) throws java.lang.AssertionError {
if ( booleanExpression ) {
// No code needed here.
} else { // If booleanExpression is false rather than expected true, throw assertion error.
// FIXME: Add logging.
throw new java.lang.AssertionError( message.toString() );
}
}
}
Example usage:
Assertions.assertTrue(
localTime.isBefore( LocalTime.NOON ) ,
"The time-of-day is too late, after noon: " + localTime + ". Message # 816a2a26-2b95-45fa-9b0a-5d10884d819d."
) ;
Your questions
They arrived relatively late (Java 1.4), by which time many people had already established their Java programming style/habit
Yes, this is quite true. Many people were disappointed by the API that Sun/JCP developed for assertion-testing. Its design was lackluster in comparison to existing libraries. So many ignored the new API, and stuck with known tools (3rd-party tools, or roll-your-own mini-library).
They are turned off at runtime by default, WHY OH WHY??
In the earliest years, Java got a bad rap for poor performance speed. Ironically, Java quickly evolved to become one of the best platforms for performance. But the bad rap hung around like a stinky odor. So Sun was extremely wary of anything that might in any measurable way impact performance. So in this perspective, it made sense to make disabling assertion-testing the default.
Another reason to disable by default might have been related to the fact that, in adding the new assertion facility, Sun had hijacked the word assert. This was not a previously reserved keyword, and required one of the few changes ever made to the Java language. The method name assert had been used by many libraries and by many developers in their own code. For some discussion of this historical transition, read this old documentation, Programming With Assertions.
Assertions are very limited: You can only test boolean conditions and you need to write the code for a useful error message every time. Compare this to JUnit's assertEquals() which allows to generate a useful error message from the inputs and even show the two inputs side by side in the IDE in a JUnit runner.
Also, you can't search for assertions in any IDE I've seen so far but every IDE can search for method invocations.
In fact they arrived in Java 1.4.
I think the main problem is that when you code in an environment where you do not manage JVM options directly by yourself like in Eclipse or J2EE servers (in both cases it is possible to change JVM options, but you need to deeply search to find where it can be done), it is easier (I mean it requires less effort) to use if and exceptions (or worse not to use anything).
As others have stated: assertions are not appropriate for validating user input.
If you are concerned with verbosity, I recommend you check out a library I wrote: https://github.com/cowwoc/requirements.java/. It'll allow you to express these checks using very little code, and it'll even generate the error message on your behalf:
requireThat("name", value).isNotNull();
and if you insist on using assertions, you can do this too:
assertThat("name", value).isNotNull();
The output will look like this:
java.lang.NullPointerException: name may not be null

Categories