In the context of a GWT application (gwt: creating an instance of Window causes application to hang out), I was setting the value to a text widget which I forgot to initialize, resulting something similar to a null pointer exception in the browser console.
What bothers me is that Eclipse displayed no warnings/errors. So I checked with the following example:
Object obj;
//obj = new Object();
obj.toString();
Eclipse says:
The local variable obj may not have been initialized
But when obj is a field of the class, I get no warning:
public class MyClass
{
Object obj;
public MyClass()
{
//obj = new Object();
obj.toString();// I expect to get some warning here
}
}
I go to Window > Preferences > Java > Compiler > Errors/Warnings, I filter using the text 'null', and the only relevant results are under the section called 'Null analysis'; here, Null pointer access is already set to raise a Warning; Potential null pointer access is set to Ignore, I modify it to raise a Warning, but i still get no warning for the above example. Is there any other way to tell the compiler to alert me about situations like this?
I googled a bit and I came across Eclipse's reporting bug system, and I saw this line from the writers:
An unassigned variable is not assigned by default and the user is expected to assign it in all possible branches of the code, or a compile time error occurs.
And also:
only fields get a default value. Local variables need to be initialized in all possible paths.
So their line of thinking is that they need you to initialize the variable whenever you need it, and it should be compiler's problem if you haven't done it, and it is no problem as far as lexical, syntax and semantic analyzers are concerned. This is why the warning is not raised.
Related
I have a problem in my SelectOutput element. The input type is "Customer", and in the Java code this is reflected correctly with the "agent" function parameter having type "Customer". However, when I access this "agent" parameter it is no longer a "Customer" type, but "StockItem" - another one of my agent types which isn't involved in this flow chart.
Error message in comment in code below:
private boolean _hasBought_condition_xjal( final com.anylogic.libraries.processmodeling.SelectOutput<Customer> self, Customer agent ) {
boolean _value;
_value = (Customer)(agent).buyingItem!=null; // <-- Error here "Description: Cannot cast from StockItem to Customer. Location: CW2_shop_2/Shop/hasBought - SelectOutput"
return _value;
}
It makes even less sense because the exact same cast works in the "On Enter" field below it, here is the setup of the SelectOutput:
I need to access a parameter of the Customer agent accessing it with "agent.buyingItem" throws an error that "type StockItem does not have parameter buyingItem", which lead me to try and cast it first as you see above.
I've already tried restarting AnyLogic and rebuilding.
Thanks in advance.
EDIT:
After discovering that I didn't need the type casting to Customer and removing it, I still find that the values between "Condition" and "onEnter" are different. I added lots of debug lines and you can see the output in the image below. The values of "agent.buyingItem!=null" seem to change. "notNull: true" is printed, but then the agent leaves through false no matter the value.
buyingItem is a variable of type StockItem, which is a blank agent.
Your brackets are wrong.
(Customer)(agent).buyingItem is getting buyingItem (presumably of type StockItem) and then trying to cast that to Customer.
You should be doing
((Customer) agent).buyingItem
Your on-enter code is correct, hence the different outputs.
in the condition you should do the following
agent.buyingItem!=null
your agent is already a customer so no need to cast it to a customer like you are trying to do and doing (agent) instead of agent does not work and might have a different meaning.
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*/);
I have a peace of code that is poorly written, like so:
HashMap<String, TceFile> mapPresetLastKdf = new HashMap<String, TceFile>( (HashMap<String, TceFile>) RsessionVars.get( sessionVars, Constants.SVAR_ENC_PRESET_LAST_KDF_MAP ) );
HashMap<String, String> mapPresetApid = new HashMap<String, String >( (HashMap<String, String >) RsessionVars.get( sessionVars, Constants.SVAR_ENC_PRESET_APID_MAP ) );
Clearly, first line fails if RsessionVars.get returns null. In that case second line is never executed.
However, Eclips IDE does not signal this failure to me, it continues executing as all is OK.
I am affraid I have many places in the code like this one. How can I detect those?
How can I force Eclipse to stop and report error on lines like this?
Edit:
This seems to be problem with exception handling.
HashMap<String, TceFile> mymap = new HashMap<String, TceFile>( null );
This should report null pointer exception.
Why is this exception not visible anywhere?
There's a difference between an exception, which you can catch, and the logical cause of the exception, which you can not catch at all. In this case, the returning and subsequent setting of the null value is a valid thing to do. It's likely in a subsequent statement that you try to send this variable (and therefore a null) some method and you're getting a null pointer exception.
In cases like this, you can only break on the subsequent null pointer exception, realize that that the cause is a null value in your variable and then to go back and debug again using breakpoints in the code to see where that null value came from.
You probably want to break the code up into multiple lines and either use a conditional breakpoint (which you can do by right clicking the line numbers if you have them displayed) or use an if statement with a normal breakpoint.
I've had trouble with conditional breakpoints and eclipse in the past so I usually go with the latter.
You could go around eclipse and write something that notifies you of the error before creating the HashMaps:
if (RsessionVars.get(sessionVars, Constants.SVAR_ENC_PRESET_LAST_KDF_MAP) == null)
System.out.println("RsessionVars.get() returned null");
Maybe your workspace is not setted correctly to handle such errors. If you go under Window -> Preferences -> Java -> Debug you should have a list of options available. The one you might want to look into is the "Suspend execution on uncaught exceptions". If checked, Eclipse will put an automatic breakpoint if the exception is not caught.
Also, if you ever know what type of exception might be, you can add a "Java Exception Breakpoint", available in the Debug/Breakpoint window (the "J" with and exclamation mark), it's an useful feature when you know what you are searching. Other than that, seperating your code in multiple lines is easier to read and to debug.
I have eclipse, and when I try to see if an uninitialized object equals null, it won't let me, it comes up with a "x might not have been intialized" error and I know it should work.
example of what I mean:
Object obj;
System.out.println(obj==null ? "no value":"has a value");
it would not compile and it would say 'obj might not have been initialized' How can I change my compiler settings in eclipse to fix this?
How can I change my compiler settings in eclipse to fix this?
You can't. The Java language specification requires any conformant Java compiler to treat this as a compilation error.
There is no Eclipse compiler setting to cause it to break this rule.
Even (hypothetically) if there was such a setting, I think that the bytecode file would fail verification when the JVM attempted to load it. (If you could somehow trick the JVM into using the value of an uninitialized local variable, that would undermine runtime type security, leading to JVM crashes ... and worse.)
If obj was an instance variable rather than a local variable, it would be default initialized to null and you wouldn't get a compilation error. But local variables are not default initialized.
You don't change the compiler settings in eclipse to fix this: you just initialize the variable obj.
Object obj = null;
System.out.println(obj==null ? "no value":"has a value");
From the Java Specification 4.12.5 - Initial Values of Variables:
A local variable (§14.4, §14.14) must be explicitly given a value before it is used, by either initialization (§14.4) or assignment (§15.26), in a way that can be verified using the rules for definite assignment (§16).
If you're really bent on not initializing obj you need to make it a member of a class instead of a local variable. Then it will have a default initial value: (again, refer to Java Specification 4.12.5 - Initial Values of Variables)
public class Example {
private static Object obj;
public static void main(String[] argv) throws Exception {
System.out.println(obj==null ? "no value":"has a value");
}
}
... but under the hood it's still getting initialized.
The compiler shows error because the rule is that all local variables must be initialized before they are first read. So first declare local variable without initializing it, initialize it later, and then use it:
Object obj = null;
System.out.println(obj==null ? "no value":"has a value");
That's a local variable, you need to initialise it with:
Object obj = null;
While certain fields of classes and objects, and arrays, may be implicitly initialised to useful defaults, that is not the case for local variables.
Section 16.2.4 (Local variable declaration statements) of JLS7 is the section to read if you want to understand this but it will take some time to understand, it's pretty obtuse :-)
You'd probably want to start at the top of section 16 (Definite Assignment) and work through from there. The first part of that has two paragraphs which are most pertinent here (my italics for emphasis):
For every access of a local variable or blank final field X, X must be definitely assigned before the access, or a compile-time error occurs.
Such an assignment is defined to occur if and only if either the simple name of the
variable (or, for a field, its simple name qualified by this) occurs on the left hand
side of an assignment operator.
How can I change my compiler settings in eclipse to fix this?
The solution is to fix your code. The purpose of this error is to detect and prevent bugs. Taking steps to allow broken code to compile is usually a very bad idea.
For this Java code:
String var;
clazz.doSomething(var);
Why does the compiler report this error:
Variable 'var' might not have been initialized
I thought all variables or references were initialized to null. Why do you need to do:
String var = null;
??
Instance and class variables are initialized to null (or 0), but local variables are not.
See §4.12.5 of the JLS for a very detailed explanation which says basically the same thing:
Every variable in a program must have a value before its value is used:
Each class variable, instance variable, or array component is initialized with a default value when it is created:
[snipped out list of all default values]
Each method parameter is initialized to the corresponding argument value provided by the invoker of the method.
Each constructor parameter is initialized to the corresponding argument value provided by a class instance creation expression or explicit constructor invocation.
An exception-handler parameter is initialized to the thrown object representing the exception.
A local variable must be explicitly given a value before it is used, by either initialization or assignment, in a way that can be verified by the compiler using the rules for definite assignment.
It's because Java is being very helpful (as much as possible).
It will use this same logic to catch some very interesting edge-cases that you might have missed. For instance:
int x;
if(cond2)
x=2;
else if(cond3)
x=3;
System.out.println("X was:"+x);
This will fail because there was an else case that wasn't specified. The fact is, an else case here should absolutely be specified, even if it's just an error (The same is true of a default: condition in a switch statement).
What you should take away from this, interestingly enough, is don't ever initialize your local variables until you figure out that you actually have to do so. If you are in the habit of always saying "int x=0;" you will prevent this fantastic "bad logic" detector from functioning. This error has saved me time more than once.
Ditto on Bill K. I add:
The Java compiler can protect you from hurting yourself by failing to set a variable before using it within a function. Thus it explicitly does NOT set a default value, as Bill K describes.
But when it comes to class variables, it would be very difficult for the compiler to do this for you. A class variable could be set by any function in the class. It would be very difficult for the compiler to determine all possible orders in which functions might be called. At the very least it would have to analyze all the classes in the system that call any function in this class. It might well have to examine the contents of any data files or database and somehow predict what inputs users will make. At best the task would be extremely complex, at worst impossible. So for class variables, it makes sense to provide a reliable default. That default is, basically, to fill the field with bits of zero, so you get null for references, zero for integers, false for booleans, etc.
As Bill says, you should definitely NOT get in the habit of automatically initializing variables when you declare them. Only initialize variables at declaration time if this really make sense in the context of your program. Like, if 99% of the time you want x to be 42, but inside some IF condition you might discover that this is a special case and x should be 666, then fine, start out with "int x=42;" and inside the IF override this. But in the more normal case, where you figure out the value based on whatever conditions, don't initialize to an arbitrary number. Just fill it with the calculated value. Then if you make a logic error and fail to set a value under some combination of conditions, the compiler can tell you that you screwed up rather than the user.
PS I've seen a lot of lame programs that say things like:
HashMap myMap=new HashMap();
myMap=getBunchOfData();
Why create an object to initialize the variable when you know you are promptly going to throw this object away a millisecond later? That's just a waste of time.
Edit
To take a trivial example, suppose you wrote this:
int foo;
if (bar<0)
foo=1;
else if (bar>0)
foo=2;
processSomething(foo);
This will throw an error at compile time, because the compiler will notice that when bar==0, you never set foo, but then you try to use it.
But if you initialize foo to a dummy value, like
int foo=0;
if (bar<0)
foo=1;
else if (bar>0)
foo=2;
processSomething(foo);
Then the compiler will see that no matter what the value of bar, foo gets set to something, so it will not produce an error. If what you really want is for foo to be 0 when bar is 0, then this is fine. But if what really happened is that you meant one of the tests to be <= or >= or you meant to include a final else for when bar==0, then you've tricked the compiler into failing to detect your error. And by the way, that's way I think such a construct is poor coding style: Not only can the compiler not be sure what you intended, but neither can a future maintenance programmer.
I like Bill K's point about letting the compiler work for you- I had fallen into initializing every automatic variable because it 'seemed like the Java thing to do'. I'd failed to understand that class variables (ie persistent things that constructors worry about) and automatic variables (some counter, etc) are different, even though EVERYTHING is a class in Java.
So I went back and removed the initialization I'd be using, for example
List <Thing> somethings = new List<Thing>();
somethings.add(somethingElse); // <--- this is completely unnecessary
Nice. I'd been getting a compiler warning for
List<Thing> somethings = new List();
and I'd thought the problem was lack of initialization. WRONG. The problem was I hadn't understood the rules and I needed the <Thing> identified in the "new", not any actual items of type <Thing> created.
(Next I need to learn how to put literal less-than and greater-than signs into HTML!)
I don't know the logic behind it, but local variables are not initialized to null. I guess to make your life easy. They could have done it with class variables if it were possible. It doesn't mean you have to have it initialized in the beginning. This is fine :
MyClass cls;
if (condition) {
cls = something;
else
cls = something_else;
Sure, if you've really got two lines on top of each other as you show- declare it, fill it, no need for a default constructor. But, for example, if you want to declare something once and use it several or many times, the default constructor or null declaration is relevant. Or is the pointer to an object so lightweight that its better to allocate it over and over inside a loop, because the allocation of the pointer is so much less than the instantiation of the object? (Presumably there's a valid reason for a new object at each step of the loop).
Bill IV