What's wrong with the following code in java [duplicate] - java

This question already has answers here:
What does a "Cannot find symbol" or "Cannot resolve symbol" error mean?
(18 answers)
Closed 5 years ago.
I am new to exception handling in java.
I was just trying to clear my concepts,but i encountered the following problem.
Here is the code.
class Inn {
public static void main(String... args) {
try{
String i="Asd";
} catch(Exception e) {
System.out.println(e);
}
//i=7;
System.out.println(i);
}
}
And here is the error which is coming.
G:\javap>javac Inn.java
Inn.java:13: error: cannot find symbol
System.out.println(i);
^
symbol: variable i
location: class Inn
1 error

try { // Block A
String i="Asd";
} // End of Block A
catch(Exception e) {
System.out.println(e);
}
System.out.println(i); // 'i' does not exist in this scope
The variable i is declared within the code block A, which means that it could only be accessible from inside of it (notice the { curly braces } that limit its scope). As soon as the execution flow passes by the block A, the variable i will no longer exist in scope.
That being said, if you want to make this work, you gonna have to declare the string i out of the inner scope:
String i = ""; // necessary initialization, without it you'll get a
// "variable may have not been initialized" error
try {
i = "Asd";
}
catch(Exception e) {
System.out.println(e);
}

The i variable is defined in a different scope and is not visible at the point where you are trying to print it.
Rewrite is as:
import java.io.*;
class Inn
{
public static void main(String s[])
{
String i = null;
try{
i="Asd";
}catch(Exception e)
{
System.out.println(e);
}
//i=7;
System.out.println(i);
}
}
That way, variable i is in the same scope as the println statement.

With most programming languages, one generally associates a scope to a variable. What the scope means in layman terms is - the section of code where the variable can be used or where the variable is visible.
With Java (or many OOP languages for that matter) we generally have various levels of scope :
Class Level Scope : Variables defined in the class i.e the member variables can be accessed anywhere within the class (I'm keeping the static modifier out of the picture for the sake of simplicity). These variables are generally defined at the top of the class (convention). Keep in mind that these variables need to be outside the methods of the class to be in the class level scope.
public class Example {
private String a; // variable a can be accessed anywhere inside the class
}
Method Level Scope : Variables defined within a method can be accessed inside the method only. Their lifetime ends when the method returns.
private int giveMeFive(){
int a = 5; // Scope of a is within the method
return a; // When a is returned then there the variable a dies :(
}
Loop Level Scope : Variables you define within the loops are restricted to that loop and any inner loops. They cannot be accessed outside the loop in which they are defined.
public static void main(String []args){
for(int i=0;i<10;i++){
System.out.println(i); // Only i is accessible here but not j
for(int j=1;j<5;j++){
System.out.println(i+j); // Both i and j are accessible here
}
}
}
Block level scope : In general, whatever resides inside of curly brackets { } defines a particular scope. In Java you can usually access a variable as long as it was defined within the same set of brackets or any brackets within these brackets.
In your case you defined the variable i within the try block so as soon as the try block finished the variable was no longer visible and hence could not be found by your println statement later on in the code.
public static void main(String[] args){
String i; // i defined outside the try block so it can be accessed after the try finished running
try{
i= "Asd"
}catch(Exception e){
Sytem.out.println(e);
}
System.out.println(i);
}
All the best :)

It is because the scope of i is juste in try block.

Variable i is defined inside the try block, which restricts the scope of i inside try block. You need to define it outside the try block.

Java is an scoped language, therefore the visivility of a variable depends of where it is defined.
In computer programming, the scope of a name binding – an association of a name to an entity, such as a variable – is the part of a computer program where the binding is valid: where the name can be used to refer to the entity.
Java is lexically scoped.
Problem with "scopes" of variables in try catch blocks in Java
Because your string i was declared in the try block, the println method is not able to find it. (it is out of scope)

Related

Static block and Forward reference [duplicate]

Analyzing some weird scenarios in following static block :
static {
System.out.println("Inside Static Block");
i=100; // Compilation Successful , why ?
System.out.println(i); // Compilation error "Cannot reference a field before it is defined"
}
private static int i=100;
While same code is working fine while using :
static {
System.out.println("Inside Static Block");
i=100; // Compilation Successful , why ?
System.out.println(MyClass.i); // Compiles OK
}
private static int i=100;
Not sure why variable initialization do not need variable access using class name while SOP requires ?
This is because of the restrictions on the use of Fields during Initialization. In particular, the use of static fields inside a static initialization block before the line on which they are declared can only be on the left hand side of an expression (i.e. an assignment), unless they are fully qualified (in your case MyClass.i).
So for example: if you insert int j = i; right after i = 100; you would get the same error.
The obvious way to solve the issue is to declare static int i; before the static initialization block.
this is because compilers doing static code analysis, for example the live variable analysis (backward analyze). It calculates for each program point whether the variable will be read before the next write.

Why attempt to print uninitialized variable does not always result in an error message

Some may find it similar to the SO question Will Java Final variables have default values? but that answer doesn't completely solve this, as that question doesn't directly print the value of x within instance initializer block.
The problem arises when I try to print x directly inside the instance initializer block, while having assigned a value to x before the end of the block :
Case 1
class HelloWorld {
final int x;
{
System.out.println(x);
x = 7;
System.out.println(x);
}
HelloWorld() {
System.out.println("hi");
}
public static void main(String[] args) {
HelloWorld t = new HelloWorld();
}
}
This gives a compile time error stating that variable x might not have been initialized.
$ javac HelloWorld.java
HelloWorld.java:6: error: variable x might not have been initialized
System.out.println(x);
^
1 error
Case 2
Instead of directly printing, I am calling a function to print:
class HelloWorld {
final int x;
{
printX();
x = 7;
printX();
}
HelloWorld() {
System.out.println("hi");
}
void printX() {
System.out.println(x);
}
public static void main(String[] args) {
HelloWorld t = new HelloWorld();
}
}
This compiles correctly and gives output
0
7
hi
What is the conceptual difference between the two cases?
In the JLS, §8.3.3. Forward References During Field Initialization, its stated that there's a compile-time error when:
Use of instance variables whose declarations appear textually after the use is sometimes restricted, even though these instance variables
are in scope. Specifically, it is a compile-time error if all of the
following are true:
The declaration of an instance variable in a class or interface C appears textually after a use of the instance variable;
The use is a simple name in either an instance variable initializer of C or an instance initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
The following rules come with a few examples, of which the closest to yours is this one:
class Z {
static int peek() { return j; }
static int i = peek();
static int j = 1;
}
class Test {
public static void main(String[] args) {
System.out.println(Z.i);
}
}
Accesses [to static or instance variables] by methods are not checked in this way, so the code above produces output 0, because the variable initializer for i uses the class method peek() to access the value of the variable j before j has been initialized by its variable initializer, at which point it still has its default value (§4.12.5 Initial Values of Variables).
So, to summarize, your second example compiles and executes fine, because the compiler does not check if the x variable was already initialized when you invoke printX() and when printX() actually takes place at Runtime, the x variable will be assigned with its default value (0).
Reading the JLS, the answer appears to be in section 16.2.2:
A blank final member field V is definitely assigned (and moreover is not definitely unassigned) before the block (§14.2) that is the body of any method in the scope of V and before the declaration of any class declared within the scope of V.
This means that when a method is called, the final field is assigned to its default value 0 before invoking it, so when you reference it inside the method, it compiles successfully and prints the value 0.
However, when you access the field outside of a method, it is considered unassigned, hence the compilation error. The following code will also not compile:
public class Main {
final int x;
{
method();
System.out.println(x);
x = 7;
}
void method() { }
public static void main(String[] args) { }
}
because:
V is [un]assigned before any other statement S of the block iff V is [un]assigned after the statement immediately preceding S in the block.
Since the final field x is unassigned before the method invocation, it is still unassigned after it.
This note in the JLS is also relevant:
Note that there are no rules that would allow us to conclude that V is definitely unassigned before the block that is the body of any constructor, method, instance initializer, or static initializer declared in C. We can informally conclude that V is not definitely unassigned before the block that is the body of any constructor, method, instance initializer, or static initializer declared in C, but there is no need for such a rule to be stated explicitly.
The difference is that in the first case you are calling System.out.println from initializer block so the block which is invoked before constructor. In the first line
System.out.println(x);
variable x is not yet initialized so that you get compilation error.
But in the second case you call instance method which doesn't know if variable has already been initialized so you don't have compilation error and you can see the default value for x
Ok, here is my 2 cents.
We all know that final variables can be initialized only While declaring or later on in constructors. Keeping that fact in mind, let see what happened here so far.
No errors Case:
So when you use inside a method, it have already a value.
1) If you initialize it, that value.
2) If not, the default value of data type.
Error case :
When you do that in an initialization block, which you are seeing errors.
If you look at the docs of initialization block
{
// whatever code is needed for initialization goes here
}
and
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.
In compiler's eye, your code is literally equals to
class HelloWorld {
final int x;
HelloWorld() {
System.out.println(x); ------------ ERROR here obviously
x = 7;
System.out.println(x);
System.out.println("hi");
}
public static void main(String[] args) {
HelloWorld t = new HelloWorld();
}
}
You are using it before even initializing it.
Case 1 :
Gives you a compile-error,
Because at System.out.println(x);
you are trying to print x which was never initialized.
Case 2:
Works because you are not directly using any literal values, instead you are calling some method, which is correct.
General Rule is,
If you are trying to access any variable which is never initialized
then it will give a compilation error.
We deal here with initializer block. The Java compiler copies initializer blocks into every constructor.
The compiler error don't occure in second example, because printing x is in another Frame, please refer to spec.

java. redeclare class field within class initializer and local variable within method nested block(framed braces) differences

I prepare for scjp exam and noticed surprising behaviour for me.
public class Test {
int k;
{
int k; // it is valid variant
}
public static void main(String[] args) {
int kk;
{
int kk; // NOT VALID.java: variable kk is already defined in method main(java.lang.String[])
}
}
public void method (int var){
int var;//NOT VALID.java: variable var is already defined in method method(int)
}
}
Always in my mind I kept following rule:
I thought that all three variants is possible and inner definition would overlap external.
example shows that it is wrong rule.
Please clarify this situations and explain common rule for familiar situations.
P.S.
public class Test {
int k;
{
int k;
{
int k; //java: variable k is already defined in instance initializer of class Test
}
}
}
Name shadowing is explained in JLS 6.4 Shadowing and Obscuring. I put the relevant parts of it for each of your examples.
Local variables may hide fields
public class Test {
int f; // field declaration
{ // init block
int f; // WARNING: Local variable f is hiding a field from type Test
}
}
Since this piece of code is declared directly in a class, the first int f; defines a field, and the block is in fact an initializer block. The init block declares a local variable that hides the field's name within that init block. This is valid (but discouraged by a warning).
Local variables may not hide method parameters
public void method (int param){
int param; // NOT VALID
}
This is not valid because, as the JLS 6.4 clearly states:
It is a compile-time error if the name of a formal parameter is
redeclared as a local variable of the method or constructor
Local variables may not hide local variables (in the same "local space")
As the JLS 6.4 states:
It is a compile-time error if the name of a local variable v is
redeclared as a local variable of the directly enclosing method,
constructor, or initializer block within the scope of v
public static void main(String[] args) {
int local;
{
int local; // NOT VALID: local declaration in same method
}
}
Here, the second statement tries to declare the same name, as another local variable of the same directly enclosing method, and within the scope of the former declaration. Not valid.
public class Test {
int f; // field declaration
{ // init block
int f; // VALID: local declaration hiding field
{ // nested local block
int f; // NOT VALID: local declaration in same init block
}
}
}
Here, the first statement declares a field. Then an init block starts, and a local variable is declared, obscuring the field's name (this 2nd declaration is valid). Now, a nested block is declared, with another local variable (3rd declaration) of the same directly enclosing init block and within the scope of the 2nd declaration. Not valid.

declaration of variable inside a loop vs multiple declarations of the same variable name

the following code gives an error, because the variable m was defined twice.
class one {
public static void main(String args[]) {
int m=10;
int m=10;
}
}
but when the declaration is done inside a loop, it is OK, even though m is still being defined twice.
class one {
public static void main(String args[]) {
for(int i=1;i<=2;i++) {
int m=10;
}
}
}
and the compiler does not give back an error message.
can you explain the differences between the two, and how come sometimes i can declare the same variable twice inside the same method, and sometimes not?
For the first case m is referenced till the end of the main method so you can't have two variable of the same name in the same scope.
Whereas in the second case, for every time the loop executes, m for the last iteration is no longer referenced and hence you are able to redeclare and reinitialize it.
You cannot declare a variable with the same name more than once in a block of code.
In first case, you are declaring the same variable in a block of code i.e. main.
In second case, after the first iteration of for loop, variable m is destroyed and recreated over the second iteration
It's creating an error in the first one because you are declaring the varible twice.
you get the error is because you defined the same variable twice in the same block (scope). when you run inside a loop, you "open" a new scope for every iteration of the loop, so you can define a variable that is visible only within this scope (won't be accible outside the loop though). for instance, if you had written something like that:
class one {
public static void main(String args[]) {
{
int m=10;
}
{
int m=10;
}
}
}
it would have been compiled just fine, because the variables of the same name, does not share the same scope.
- In the First code you have declared m twice in the same scope, and it continues till the main() method ends.
- Where as within the loop everytime a primitive int variable m is created with a value, so its obviously not a problem.
In simple words, you are not declaring this variable twice in second example. As variable lifespan ends on the closing } of the block in which it was declared, by the time you declare m in second iteration, first one is "dead". This is why you can do it in a loop.
In first example you declare two variables with the same name in the same code block, which are supposed to "live" simultaneously. This is forbidden as you can't tell which variable you refer too by writing m.

Why does a Try/Catch block create new variable scope?

For example:
try
{
SomeObject someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); //can't access someObject!
But you can declare it before the try/catch block and then it works fine:
SomeObject someObject;
try
{
someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); //works fine
I'm just wondering the design reason for this. Why are Objects created within the try/catch block not in scope with the rest of the method? Maybe I'm not understanding deep down how a try/catch works besides just watching for Exceptions thrown.
Why are Objects created within the try/catch block not in scope with the rest of the method?
They are. Variables declared within the try/catch block are not in scope in the containing block, for the same reason that all other variable declarations are local to the scope in which they occur: That's how the specification defines it. :-) (More below, including a reply to your comment.)
Here's an object created within a try/catch which is accessible outside of it:
SomeObject someObject = null;
try
{
someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); // This is fine -- unless the SomeObject
// constructor threw the exception, in which
// case someObject will be null
Note the difference. Where the variable is declared defines the scope in which it exists, not where the object was created.
But based on the method names and such above, the more useful structure for that would be:
SomeObject someObject = new SomeObject();
try
{
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod();
Re your comment:
I guess I'm confused as to why another scope has even been created for a try/catch block.
In Java, all blocks create scope. The body of an if, the body of an else, of a while, etc. — they all create a new, nested variable scope:
if (foo) {
SomeObject bar = new SomeObject();
}
bar.doSomething(); // <== Compilation error, `bar` is not defined
(In fact, even a block without any control structure creates one.)
And if you think about it, it makes sense: Some blocks are conditional, like the one defining the body of an if or while. In the above if, bar may or may not have been declared (depending on the value of foo), which makes no sense because of course the compiler has no concept of the runtime value of foo. So probably for consistency, the designers of Java went with having all blocks create a new nested scope. (The designer of JavaScript went the other way — there is no block scope at all, yet, though it's being added — and that approach also confuses people.)
In Java, any time you have a { } pair, you can create a new scope.
Consider the following
class ScopeTest {
public static void main(String[] args) {
int i = 0;
{ int j = 0; System.out.println(j); }
{ int j = 2; System.out.println(j); }
}
}
The try/catch just follows this idiom, and enforces a { } pair to be created.
To respond to your followup of a non-bracketed if statement, consider:
class MultiRTree {
public static void main(String...args) {
boolean b = args.length == 0;
if(b) String s = new String("hello");
}
}
results in
c:\files\j>javac ScopeTest.java
ScopeTest.java:4: not a statement
if(b) String s = new String("hello");
^
ScopeTest.java:4: ';' expected
if(b) String s = new String("hello");
^
2 errors
However, this will compile just fine.
class ScopeTest {
public static void main(String...args) {
boolean b = args.length == 0;
if(b) new String("hello");
}
}
Why this is so, according to the JLS Chapter 14, section 9, if is defined as:
IfThenStatement:
if ( Expression ) Statement
And Statement is defined as (14.5)
Statement:
StatementWithoutTrailingSubstatement
LabeledStatement
IfThenStatement
IfThenElseStatement
WhileStatement
ForStatement
StatementWithoutTrailingSubstatement:
Block
EmptyStatement
ExpressionStatement
AssertStatement
SwitchStatement
DoStatement
BreakStatement
ContinueStatement
ReturnStatement
SynchronizedStatement
ThrowStatement
TryStatement
So a block, expression statement, or empty statement those are just fine. But a declaration (defined in chapter 6) is not in the grammar of statement.
Every time you do use a bracket '{' you're expressing a new scope in both C++ and Java. You're attempt to try an operation requires some internal setup and scoping the names allows for quick jumps back out of the try block without a lot of cleanup.
Some languages will let you access those scoped variables outside of the scope as long as there isn't a name conflict (like in Python), but this requires an slightly different internal stack structure and could still increase the costs of the try catch regardless.
Also it's just how scope definitions are defined in Java -- as many of the other answers pointed out.
The scope of a variable or object is in the scope (defined by curly braces {}) in which it is defined.
Since try catch initiates a new scope where some error can be thrown so the objects defined inside try catch are not available outside it's scope.
try/catch creates a new scope for the simple reason that it is a block level element. In fact, simply placing {} just randomly inside a method will create a new block of code with it's own local scope.

Categories