Consider a private method which is called from JNI and not used otherwise, generating a compiler warning about an unused method:
private void someMethodCalledOnlyFromJNI() { // WARNING: method is never used
// ....
}
This is some legacy code in Java 1.4 - so no dice on #SuppressWarnings.
What hack would you use to suppress this compiler warning?
Edit: Obviously this is just a warning and it can easily be ignored. But, personally, I hate warnings in my code just as much as I don't want to see errors in it. AFAIC - my code should have 0 warnings, it might be an exaggeration, but I am very pedantic about this.
Just as an example, someone might see this function, not know it is used from JNI, and simply delete it.
Ignore it. It is a warning, after all - best option
use protected (and add a comment for the reason why) - bearable
Make a dummy method just above it and make the two call each other (again with comments) - ugly
configure the IDE not to show this warning at all (in eclipse it is Windows > Preferences > Java > Compiler > Errors/Warnings) - not preferable
As per your update: having 0 warnings is not a goal you should set. The number of warnings depends on the settings, so if you don't all have unified IDEs, this number will vary. And then you can add checkstyle / PMD to report warnings as well - then you'll have even more. The reasonable behaviour is to have a warnings treshold.
If you don't want anyone to delete this method, just add a comment:
// This method is used is used by JNI. (Don't delete)
Somewhere else in the class:
if(Boolean.FALSE.booleanValue())
{ // prevents warning for unused private method which is used from JNI
someMethodCalledOnlyFromJNI();
}
(can't use simple false because that results in dead code warning).
Either just ignore the warning, or declare it as protected instead. If you go for protected and want to prevent subclassing/overriding as well, then declare it final as well.
To start with, its only a warning, thus it should not be an issue for you.
You could either mod the code to remove that function thus removing the problem.
Or just call it from some where at the start/end of your code and ignore any results. As long as it is not going to try to set up any thing that will affect the rest of your program you will be fine.
you can make it public. if it's legacy code I am sure no one will complain :)
Related
I have a program that basically looks like this:
boolean[] stuffNThings;
int state=1;
for(String string:list){
switch(state){
case 1:
if(/*condition*/){
// foo
break;
}else{
stuffNThings=new boolean[/*size*/];
state=2;
}
// intentional fallthrough
case 2:
// bar
stuffNThings[0]=true;
}
}
As you, a human, can see, case 2 only ever happens when there was previously a state 1 and it switched to state 2 after initialising the array. But Eclipse and the Java compiler don't see this, because it looks like pretty complex logic to them. So Eclipse complains:
The local variable stuffNThings may not have been initialized."
And if I change "boolean[] stuffNThings;" to "boolean[] stuffNThings=null;", it switches to this error message:
Potential null pointer access: The variable stuffNThings may be null at this location.
I also can't initialise it at the top, because the size of the array is only determined after the final loop in state 1.
Java thinks that the array could be null there, but I know that it can't. Is there some way to tell Java this? Or am I definitely forced to put a useless null check around it? Adding that makes the code harder to understand, because it looks like there may be a case where the value doesn't actually get set to true.
Java thinks that the array could be null there, but I know that it can't.
Strictly speaking, Java thinks that the variable could be uninitialized. If it is not definitely initialized, the value should not be observable.
(Whether the variable is silently initialized to null or left in an indeterminate state is an implementation detail. The point is, the language says you shouldn't be allowed to see the value.)
But anyway, the solution is to initialize it to null. It is redundant, but there is no way to tell Java to "just trust me, it will be initialized".
In the variations where you are getting "Potential null pointer access" messages:
It is a warning, not an error.
You can ignore or suppress a warning. (If your correctness analysis is wrong then you may get NPE's as a result. But that's your choice.)
You can turn off some or all warnings with compiler switches.
You can suppress a specific warning with a #SuppressWarnings annotation:
For Eclipse, use #SuppressWarnings("null").
For Android, use #SuppressWarnings("ConstantConditions").
Unfortunately, the warning tags are not fully standardized. However, a compiler should silently ignore a #SuppressWarnings for a warning tag that it doesn't recognize.
You may be able to restructure the code.
In your example, the code is using switch drop through. People seldom do that because it leads to code that is hard to understand. So, I'm not surprised that you can find edge-case examples involving drop-through where a compiler gets the NPE warnings a bit wrong.
Either way, you can easily avoid the need to do drop-through by restructuring your code. Copy the code in the case 2: case to the end of the case 1: case. Fixed. Move on.
Note the "possibly uninitialized" error is not the Java compiler being "stupid". There is a whole chapter of the JLS on the rules for definite assignment, etcetera. A Java compiler is not permitted to be smart about it, because that would mean that the same Java code would be legal or not legal, depending on the compiler implementation. That would be bad for code portability.
What we actually have here is a language design compromise. The language stops you from using variables that are (really) not initialized. But to do this, the "dumb" compiler must sometimes stop you using variables that you (the smart programmer) know will be initialized ... because the rules say that it should.
(The alternatives are worse: either no compile-time checks for uninitialized variables leading to hard crashes in unpredictable places, or checks that are different for different compilers.)
A distinct non-answer: when code is "so" complicated that an IDE / java compiler doesn't "see it", then that is a good indication that your code is too complicated anyway. At least for me, it wasn't obvious what you said. I had to read up and down repeatedly to convince myself that the statement given in the question is correct.
You have an if in a switch in a for. Clean code, and "single layer of abstraction" would tell you: not a good starting point.
Look at your code. What you have there is a state machine in disguise. Ask yourself whether it would be worth to refactor this on larger scale, for example by turning it into an explicit state machine of some sort.
Another less intrusive idea: use a List instead of an array. Then you can simply create an empty list, and add elements to that as needed.
After just trying to execute the code regardless of Eclipse complaining, I noticed that it does indeed run without problems. So apparently it was just a warning being set to "error" level, despite not being critical.
There was a "configure problem severity" button, so I set the severity of "Potential null pointer access" to "warning" (and adjusted some other levels accordingly). Now Eclipse just marks it as warning and executes the code without complaining.
More understandable would be:
boolean[] stuffNThings;
boolean initialized = false;
for (String string: list) {
if (!initialized) {
if (!/*condition*/) {
stuffNThings = new boolean[/*size*/];
initailized = true;
}
}
if (initialized) {
// bar
stuffNThings[0] = true;
}
}
Two loops, one for the initialisation, and one for playing with the stuff might or might not be more clear.
It is easier on flow analysis (compared to a switch with fall-through).
Furthermore instead of a boolean[] a BitSet might used too (as it is not fixed sized as an array).
BitSet stuffNThings = new BitSet(/*max size*/);
IDEA shows a warning if a increment int with ++ or += operators.
It can only be fixed if I increment in a explicit way int=int+1.
Is it a bug or a feature?
EDIT: Ok, it's a feature of IDEA. But it seems to me wrong. We obviously can't increment something without accessing the initial state. Would we have operator overloading we can think of ++ as of a function with argument i.
So, the question is: is it possible to change this behavior in IDEA?
Its a feature, you can customise which ones show and what level of warning they give in Intellij by going to Project Settings - Insepections
There is a huge list which you can turn on and off or customise.
This one is due to the variable is never used even though you are incrementing it, it is never explicitly read by another statement.
And if you do i = i + 1 it still gives that warning just on the new assignment like so (well that's a new warning I see now)
The warning you are after is in Declaration redundancy - Unused Symbol
You can configure this for what it checks or to ignore with special annotations but not how it behaves in your instance.
I think that it is still valid for the IDE to give that warning as the operations ++ and += are only accessing it to assign it to itself... what the point if you are then not using it elsewhere.
It gives you the warning, as you are not reading the variable out, merely incrementing it.
It's a feature.
This question already has answers here:
What is SuppressWarnings ("unchecked") in Java?
(11 answers)
Closed 9 years ago.
I am learning Java. I have task to implement HashDictionary using DictionaryInterface
Hashtable<K,V> h;
Set<K> s = h.keySet();
K elements[]=(K[])Array.newInstance(KeyType, h.size());
When I have written the above statements the Eclipse IDE is showing a warning message.
#SuppressWarnings("unchecked")
If I add the above message before start of a method. The warning is disappeared. What is this means. Can anyone give the reason? Thanks in Advance
Warning in general are just that - warnings. Things that can easily go wrong, but havent technically gone wrong yet. Sometimes you are well aware of them and can simply ignore them. In those cases you might want to use #SuppressWarnings("unchecked"). That will signal the compiler to no post its warning, thus giving you an absolutely clean compile.
Note that even if you dont put that there and you do get the warning your program can still work just fine. Its just that there is an elevated chance that your program will break at that point.
If you want, you can also remove the warning entirely from eclipse by going to Windows > Preferences > General > Editors > Text Editors > Annotations > Warnings > Annotation types and then select the warnings you do/dont want.
The annotation type SuppressWarnings supports programmer control over warnings otherwise issued by the Java compiler. It contains a single element that is an array of String. If a program declaration is annotated with the annotation #SuppressWarnings(value = {someString}), then a Java compiler must not report any warning identified by one of someString if that warning would
have been generated as a result of the annotated declaration or any of its parts.
For example, Unchecked warnings are identified by the string unchecked. In your example, the below statement will emit an unchecked warning:
K elements[]=(K[])Array.newInstance(KeyType, h.size());
This statement contains an unchecked conversion, as the compiler doesn't know if the cast is safe or not; and will simply emit an unchecked conversion warning. Which can be suppressed by using #SuppressWarnings("unchecked") annotation.
In case you don't already know (you said you're a beginner), Eclipse often tells you what is causing the warning and can sometimes give you suggestions on how to fix it.
Of course, it's always much better to fix the warnings than to suppress them (unless you're doing really intricate stuff). Hope this helps.
I have a class called SQLProvider, it contains methods for both opening and closing a SQLite database connection. Using annotations or another approach, is it possible to flag a compiler warning if the open method is used without also calling close?
{
SQLProvider provider = new SQLProvider();
provider.open()
// display a compiler warning unless provider.close() is also invoked in this code block
}
I am not sure it would be the best approach but you can make your class implement Closeable interface . As per the Eclipse documenatation, Eclipse will display warning :
When enabled, the compiler will issue an error or a warning if a local variable holds a value of type 'java.lang.AutoCloseable' (compliance >= 1.7) or a value of type 'java.io.Closeable' (compliance <= 1.6) and if flow analysis shows that the method 'close()' is not invoked locally on that value.
There is currently no such facility in the standard Java toolchain.
In addition to the Eclipse compiler warnings (see New Idiot's answer), some static code analysers can warn you about this:
For PMD, the CloseResource design rule covers this (or at least some subcases ...)
FindBugs can also do this; e.g. FindBugs - "may fail to close stream" when using ObjectOutputStream
But the problem is these warnings are more or less heuristic. They only understand certain standard idioms for reliably closing resources. If you do it some other way (which is still provably reliable) they are likely to produce a false warning. This is not necessarily bad (because doing this a non-standard way is liable to fool / puzzle future readers!). However the possibility of false positives may tempt developers to ignore or (worse still) suppress the warnings.
There are a couple of additional issues:
These checks may give a false negative for resource objects that have a close() method without implementing Closeable or AutoCloseable.
These checks may give a false negative for Closeable / AutoCloseable resource objects where the close() operation is a no-op; for example, StringWriter.
These issues may explain why the standard Java toolchain doesn't support this.
I'd like a mechanism to throw a compile-time warning manually. I'm using it to flag unfinished code so I can't possibly forget about it later. #Deprecated is close but warns at caller site, not at creation site. I'm using eclipse. Something like #Warning in C#.
Why not just add a flag in the source code like //TODO: or something? And then just search for all occurances of TODO in the file? You could even have some special flag too like FINISHME or something.
If you have hundreds of TODOs in your project from the team, you can filter by a string e.g. your initials in the Task pane's top-right menus.
A lot better than using the deprecated annotation in my humble opinion the suppresswarnings annotation.
#SuppressWarnings("XXX")
can be annotated almost everywhere and as long as XXX is not a valid warning you will get a warning from eclipse about that.
Create an annotation that prints out a warning.
You could try to throw an exception if an unfinished method is called (e.g.)
throw new UnsupportedOperationException()
(Or you could create your own Exception). Obviously this will only help at runtime (unless you do a search or something in your code for it - but Todo would be a better solution for that)
And if you are using eclipse you can mark your unfinished code with // TODO and it will show up on your task list (and the right gutter if you have it configured). Obviously things can get very noisy if you have a lot of Todo tags.
I do this all the time by just putting "*** LEFT OFF HERE ***" or some such. As this is not valid Java or C++ or pretty much any other language syntax, the compiler gives an error message for it.
Of course that gives an error and not a warning. If you want to otherwise successfully compile, I suppose an easy thing to do would be to put a statement that you know will generate a compiler warning with a comment saying "finish this" or whatever.
When I want to warn users about calling a method, I (mis)use the build-in #Deprecated annotation which generates a warning at the caller side. Actually it has a slightly different meaning, but I don't care.
/** [Additional information...]
* It is marked as deprecated to warn callers. */
#Deprecated public void methodForWhichIWantToCreateAWarning();
I'm not sure if there is anything like that in java
but here is something that may help you:
compile the code below like this:
javac -Xprint verbose.java
public class verbose{
public #interface SomeMessage {
String somevalue();
}
#SomeMessage(
somevalue = "WHOOOOHOOOO000000000000000"
)
public static void main(){
System.out.println("Hello");
}
}