Java: Catch uninitialized variable - java

Suppose we have a case where a variable is declared in certain conditions:
if (x = 1)
boolean z = true;
Later on, we'd like to test if the variable z exists with try-catch. Is this possible and if so, what exception should we catch?
try {
if (z)
//do smth
} catch (<exception?> ex) {
//do smth_else
}
Of course it would be possible to declare z before and change it's value accordingly in if block, but just hypothetically, is the above possible in Java?
Python for example has NameError that will be raised when accessed local or global variable is not declared.
Thanks!
HSI.

What if you declared your variable like this:
Boolean x = null;
In that case you could check for it being null or not.
An even better alternative would be using an enum to represent the uninitialized value:
public enum MyEnum {
UNINITIALIZED, TRUE, FALSE;
}
because if you will try to maintain your code several months later you (or someone else) may be puzzled about the Boolean being null.

we'll get compilation error if the variable we are using is not declared or is not visible in current scope.
If it is declared we can check for NullPointerException if that was object. In case of primitive data types we should check for default values.

Suppose we have a case where a variable is declared in certain conditions:
Well it is difficult to assume because that would not compile:
you should use == to test for equality
you can't declare a variable in an if statement unless there is a block
Now assuming you enclose that declaration inside a block, the scope of that variable would be that block and you wouldn't be able to use it in your try / catch block (unless it is inside the if block of course, but I don't think that's what you want).

No, this is not possible in Java. You have to have the variable declared before you can refer to it, otherwise you will get a compilation error.

Boolean z = null;
if (x = 1){
z = true;
}
if(z == null){
//not initialized
}else{
//initialized
}

it's not possible, Java is a strongly typed programming language because every variable must be declared with a data type before it can be used.
int x = 1;
boolean z = null;
if (x == 1)
z = true;
try {
if (z)
//do smth
} catch (NullPointerException npe ) {
//do smth_else
}

So far I understand , you wont be able to compile this piece of code. I can not remember any exception class but what I think is even if you "Invent" exception for this type of error. It won't compile. Because default values of primitive types are assigned to uninitialized class variables called fields but for variable used in method body, it gives compile time error

Related

Variable used in lambda expression should be final or effectively final JAVA [duplicate]

Variable used in lambda expression should be final or effectively final
When I try to use calTz it is showing this error.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if (calTz == null) {
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
});
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}
Although other answers prove the requirement, they don't explain why the requirement exists.
The JLS mentions why in §15.27.2:
The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems.
To lower risk of bugs, they decided to ensure captured variables are never mutated.
This also applies for anonymous inner classes
A final variable means that it can be instantiated only one time.
in Java you can't reassign non-final local variables in lambda as well as in anonymous inner classes.
You can refactor your code with the old for-each loop:
private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
try {
for(Component component : cal.getComponents().getComponents("VTIMEZONE")) {
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if(calTz==null) {
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
}
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}
Even if I don't get the sense of some pieces of this code:
you call a v.getTimeZoneId(); without using its return value
with the assignment calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue()); you don't modify the originally passed calTz and you don't use it in this method
You always return null, why don't you set void as return type?
Hope also these tips helps you to improve.
From a lambda, you can't get a reference to anything that isn't final. You need to declare a final wrapper from outside the lamda to hold your variable.
I've added the final 'reference' object as this wrapper.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
final AtomicReference<TimeZone> reference = new AtomicReference<>();
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component->{
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if(reference.get()==null) {
reference.set(TimeZone.getTimeZone(v.getTimeZoneId().getValue()));
}
});
} catch (Exception e) {
//log.warn("Unable to determine ical timezone", e);
}
return reference.get();
}
Java 8 has a new concept called “Effectively final” variable. It means that a non-final local variable whose value never changes after initialization is called “Effectively Final”.
This concept was introduced because prior to Java 8, we could not use a non-final local variable in an anonymous class. If you wanna have access to a local variable in anonymous class, you have to make it final.
When lambda was introduced, this restriction was eased. Hence to the need to make local variable final if it’s not changed once it is initialized as lambda in itself is nothing but an anonymous class.
Java 8 realized the pain of declaring local variable final every time a developer used lambda, introduced this concept, and made it unnecessary to make local variables final. So if you see the rule for anonymous classes has not changed, it’s just you don’t have to write the final keyword every time when using lambdas.
I found a good explanation here
In your example, you can replace the forEach with lamdba with a simple for loop and modify any variable freely. Or, probably, refactor your code so that you don't need to modify any variables. However, I'll explain for completeness what does the error mean and how to work around it.
Java 8 Language Specification, §15.27.2:
Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.
Basically you cannot modify a local variable (calTz in this case) from within a lambda (or a local/anonymous class). To achieve that in Java, you have to use a mutable object and modify it (via a final variable) from the lambda. One example of a mutable object here would be an array of one element:
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
TimeZone[] result = { null };
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
...
result[0] = ...;
...
}
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return result[0];
}
A variable used in lambda expression should be a final or effectively final, but you can assign a value to a final one element array.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
try {
TimeZone calTzLocal[] = new TimeZone[1];
calTzLocal[0] = calTz;
cal.getComponents().get("VTIMEZONE").forEach(component -> {
TimeZone v = component;
v.getTimeZoneId();
if (calTzLocal[0] == null) {
calTzLocal[0] = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
});
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}
to answer to > Variable used in lambda expression should be final or effectively final JAVA
to workaround that in not an elegant way , 2 issues :
the side effect and the threading issue
final AtomicInteger e = new AtomicInteger(0);
new Thread(() -> {
e.addAndGet(1);
});
to be more precise, i agree is kind of the same but the idea behind using Lambda function is to avoid side affect, and when we are accessing this final reference in the lambda function to populate the value to get the result from outside, we are breaking this concept.
in the oldest post you might want to rewrite like that
cal.getComponents().getComponents("VTIMEZONE").streams().map(v->v.getTimeZoneId().getValue()).collect(Collectors.toList());
and for the threading aspect , we have the same issue with the side effect and additionally you will never know when to access to the Atomic variable to collect the result , you could put a CountDownLatch ... Better to work with CompletableFuture to handle the result and the synchronization aspect
if it is not necessary to modify the variable than a general workaround for this kind of problem would be to
extract the part of code which use lambda and use final keyword on method-parameter.
You can't re-assign the variable with new reference inside a lambda expression which is coming from outside scope of lambda.But you can certainly modify existing state of the object.So instead re-assigning 'calTz' to new reference.You can call setter methods on it to change its internal state.So this will work(if your VtimeZone is mutatble only):
calTz=new TimeZone();
cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
calTz.setTimeZoneId("some value");
})
.But this is not a good practice.
Above code can also be replaced by.
if(calTz == null){
calTz=new TimeZone();
cal.getComponents().getComponents("VTIMEZONE").get(0).setTimeZoneId("some value");}

Java Output Variable Scope Issue

I have an issue regarding variable scope in the following piece of code. Can someone give a quick overview as to why java "cannot find the symbol" for output when it is printed? Thanks.
class Main
{
public static void main(String[] args) {
String text = "hello";
if (text.indexOf(" ") == -1) //if a space doesn't exist
{
String output = "one word";
}
else
{
String output = "more than one word";
}
System.out.println(output);
}
}
The variable output is only existent within the containing code block which currently seems to be within the if block and else block, if you want to access the variable output outside of the if and else block, you'll need to define it before the if block.
Local variables
A local variable is the one that is declared within a method or a constructor (not in the header). The scope and lifetime are limited to the method itself.
In addition to the local variables defined in a method, we also have variables that are defined in blocks, e.g. the if block and an the else block. The scope in this case is constrained by the block itself.

Why can't we declare variables in if statement?

I know that there is a question like this on Stack Overflow but I want to know why we can't declare variables inside if statements so that we can save space by just utilizing the if scope.
For example, if I write:
if (int i) {
...
}
then I could use i only within the if scope, but if I write it outside of the if statement, then i variable should be in memory for the whole block.
if ( int i ) => int i is not a boolean expression, so this won't work.
if ( booleanExpr ){
int a = 5;
...
}
here a is a local variable within the if block. At the end of the if-block, it is removed from the stack and becomes unusable.
int a = 5;
if ( booleanExpr){
...
}
Here a is not local to the if block, but to the containing method. So, it will be on the stack during the entire execution of the method (starting from its declaration).
a could also be an instance or static variable to the class, then it's accessible in every method of the class (instance variables are not accessible in a static context, though)
why can't we declare variables in the if statement?
Because the Java Language Specification does not allow it.
if I write if(int i){} then I could use i only for if the scope
You can use blocks
public void someMethod() {
{
int i = 1; // visible only to the current block
} {
int i = 0; // visible only to the current block
if (i == 0) {
System.out.println("i = " + i);
}
}
// compiler error, because i is not visible outside the block
System.out.println(i);
}
But this decreases the readability of your code. So I would recommend to NOT use it.
An if statement is a test, so declaring a variable in an if does not make any sense.
Think about it, an if is for something like this:
if(a == 1){
// blan
}
If you declare a in the if condition, you are essentially comparing 2 static values.
Lots of languages let you declare an "iterator" vairable in a for loop:
if(int a = 0 ; a < somelist.length ; a++){
// Do something
}
// a is out of scope here
You can restrict the scope of your variable to make it visible only in the if statement like this:
System.out.println("Hello World!");
//use a codeblock to restrict access
{
int i = 4;
if(i!=0)
{
System.out.println("i = "+i);// this is OK
}
}
System.out.println("i = "+i);//this is not OK
why can't language support it
That's the wrong question to ask. The real question is:
Is there a compelling reason for the language to support it?
That is, is there a compelling reason to implement it, exhaustively test it for all possible edge cases, and maintain it in all future versions of the language?
In this case, no. There isn't. It might be handy in a small number of cases, but it's not a core feature of the language and isn't really necessary. So there's no compelling reason to make the implementation of the language more complex and incur significant cost now and well into the future to support it.
if is a conditional and there is no valid use-case when you declare a variable inside the conditional.
If your conditional is more complex, you can implement a few methods for it and inside those methods you can use those variables, however, if you need that variable outside the if, then define it outside the if in the correct scope.

Initialization of local variables

What's the difference between the declaring an uninitialized final variable and setting a final variable to null?
void A(String pizza) {
String retVal = null;
if (StringUtils.isBlank(pizza)) {
retVal = "blank"
} else {
retVal = computeString(pizza);
}
}
void A(String pizza) {
final String retVal;
if(StringUtils.isBlank(pizza)) {
retVal = "blank"
} else {
retVal = computeString(pizza);
}
}
Maybe I didn't understand, but in your second example, you won't be able to reassign retVal after your if-else block. A final variable
may only be assigned to once. Declaring a variable final can serve as
useful documentation that its value will not change and can help avoid
programming errors.
If you had set your final variable to null, you would not be able to reassign it in the if block.
If you set a final variable to null you'll never be able to assign anything else to it...
A final variable (itself) can never change.
The difference is that a final variable can never be changed to have another value.
In this one, the retVal = null accomplishes nothing. You give it a value of null. You never have code that uses that value. Then you give it another value, depending on whether you do the if-then or the else part.
In code that falls where I've added the comment, you can use or change the value of retVal.
void A(String pizza) {
String retVal = null;
... code in here could use it or give it a new value ...
if(StringUtils.isBlank(pizza) {
retVal = "blank"
} else {
retVal = computeString(pizza);
}
... additional code here might change it (and can use it's value) ...
}
In this one, you are required to give retVal a value everytime the method is called. Your if-then-else code does that. The value can never be changed after it is given a value.
One difference is that the compiler would tell you if you used retVal before giving it a value. It would, reasonably, tell you that the variable has no value yet.
void A(String pizza) {
final String retVal;
... code in here cannot use it or give it a value, too ...
if(StringUtils.isBlank(pizza) {
retVal = "blank"
} else {
retVal = computeString(pizza);
}
... additional code here cannot change it but can use it's value ...
}
final means:
You have to assign something (even if it's null)
You can't change the reference to anything else afterwards (but you can, of course, modify
the referenced object).
The meaning is highly semantic, and makes sure you won't accidentally forget to care about what to assign, and you can code with the guarantee that the value is not accidentally changed.
Omitting this modifier just removes that guarantee, nothing else.

Invisible Objects in java

The following code is part of a larger application:
public static void METHOD_NAME(Object setName, int setLength){
tryLoop:
for( ; ; ){
try{
setName = new Stack(setLength);
break tryLoop;
}catch (InstantiationException e){
System.err.println(e.getMessage());
SET_NUM(1);
continue tryLoop;
}
}
}
Whenever I try to use the stack object that was initialized within the try block, it cannot be found unless the reference to it is within the try block. Why is this and how can I avoid it in the future?
I suspect you're under the impression that this:
setName = new Stack(setLength);
will have some impact on the argument passed in by the caller. It won't. Java is strictly pass-by-value, whether that value is a primitive type value or a reference.
In other words, if you do this:
Object foo = null;
METHOD_NAME(foo, 5);
then foo will still be null afterwards.
I suggest you return the value from your method instead. For example:
public static Stack METHOD_NAME(Object setName, int setLength){
while(true) {
try {
return new Stack(setLength);
} catch (InstantiationException e){
System.err.println(e.getMessage());
SET_NUM(1);
}
}
}
Note the return instead of breaking to a label, and while(true) which I find more readable than for (; ;).
Well, that method is ... pretty unorthodox Java code, to say at least.
Additionally it doesn't seem to have any meaningful result whatsoever. It sets its own parameter to a new value (entirely ignoring the original one) and never returns anything or modifies any object that it gets passed.
So unless the construction of a Stack object has some effect that is visible from the outside, this methods doesn't do anything useful (in the "no-exception" case).
Declare a method scode variable before your try block and assign setName to it. Then assign new Stack() to that variable in your try block and return it at the end of your method.
Modifying the value of a parameter is usually bad practice anyways.
No idea what you're using a label for -- continue; will work fine. Other things are a bit suspect here too. The scope for a variable declared inside a try block is just the try block. Setting 'setName' will do nothing as Java passes an object, and changing the reference to point to a new object will not affect the passed object. As for not being able to use setName in the current bit of code, you can avoid it by taking it outside of the block, or doing everything you need to inside the try block :) You can also return it to allow the caller to use it. Why are you trying to catch InstantiationException? You'd be better off checking that setLength is a valid size and let uncaught exceptions validate the integrity of Java itself.
Java does not support pass-by-reference, so the assignment to setName does not pass any value back to the caller.
The obvious rewrite of your code is as follows:
public static Object METHOD_NAME(int setLength) {
while (true) {
try {
return new Stack(setLength);
} catch (InstantiationException e){
System.err.println(e.getMessage());
SET_NUM(1);
}
}
}

Categories