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.
Related
Is there any advantage for either approach?
Example 1:
class A {
B b = new B();
}
Example 2:
class A {
B b;
A() {
b = new B();
}
}
There is no difference - the instance variable initialization is actually put in the constructor(s) by the compiler.
The first variant is more readable.
You can't have exception handling with the first variant.
There is additionally the initialization block, which is as well put in the constructor(s) by the compiler:
{
a = new A();
}
Check Sun's explanation and advice
From this tutorial:
Field declarations, however, are not part of any method, so they cannot be executed as statements are. Instead, the Java compiler generates instance-field initialization code automatically and puts it in the constructor or constructors for the class. The initialization code is inserted into a constructor in the order it appears in the source code, which means that a field initializer can use the initial values of fields declared before it.
Additionally, you might want to lazily initialize your field. In cases when initializing a field is an expensive operation, you may initialize it as soon as it is needed:
ExpensiveObject o;
public ExpensiveObject getExpensiveObject() {
if (o == null) {
o = new ExpensiveObject();
}
return o;
}
And ultimately (as pointed out by Bill), for the sake of dependency management, it is better to avoid using the new operator anywhere within your class. Instead, using Dependency Injection is preferable - i.e. letting someone else (another class/framework) instantiate and inject the dependencies in your class.
Another option would be to use Dependency Injection.
class A{
B b;
A(B b) {
this.b = b;
}
}
This removes the responsibility of creating the B object from the constructor of A. This will make your code more testable and easier to maintain in the long run. The idea is to reduce the coupling between the two classes A and B. A benefit that this gives you is that you can now pass any object that extends B (or implements B if it is an interface) to A's constructor and it will work. One disadvantage is that you give up encapsulation of the B object, so it is exposed to the caller of the A constructor. You'll have to consider if the benefits are worth this trade-off, but in many cases they are.
I got burned in an interesting way today:
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
See the mistake? It turns out that the a = null initializer gets called after the superclass constructor is called. Since the superclass constructor calls init(), the initialization of a is followed by the a = null initialization.
my personal "rule" (hardly ever broken) is to:
declare all variables at the start of
a block
make all variables final unless they
cannot be
declare one variable per line
never initialize a variable where
declared
only initialize something in a
constructor when it needs data from
the constructor to do the
initialization
So I would have code like:
public class X
{
public static final int USED_AS_A_CASE_LABEL = 1; // only exception - the compiler makes me
private static final int A;
private final int b;
private int c;
static
{
A = 42;
}
{
b = 7;
}
public X(final int val)
{
c = val;
}
public void foo(final boolean f)
{
final int d;
final int e;
d = 7;
// I will eat my own eyes before using ?: - personal taste.
if(f)
{
e = 1;
}
else
{
e = 2;
}
}
}
This way I am always 100% certain where to look for variables declarations (at the start of a block), and their assignments (as soon as it makes sense after the declaration). This winds up potentially being more efficient as well since you never initialize a variable with a value that is not used (for example declare and init vars and then throw an exception before half of those vars needed to have a value). You also do not wind up doing pointless initialization (like int i = 0; and then later on, before "i" is used, do i = 5;.
I value consistency very much, so following this "rule" is something I do all the time, and it makes it much easier to work with the code since you don't have to hunt around to find things.
Your mileage may vary.
Example 2 is less flexible. If you add another constructor, you need to remember to instantiate the field in that constructor as well. Just instantiate the field directly, or introduce lazy loading somewhere in a getter.
If instantiation requires more than just a simple new, use an initializer block. This will be run regardless of the constructor used. E.g.
public class A {
private Properties properties;
{
try {
properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("file.properties"));
} catch (IOException e) {
throw new ConfigurationException("Failed to load properties file.", e); // It's a subclass of RuntimeException.
}
}
// ...
}
Using either dependency injection or lazy initialization is always preferable, as already explained thoroughly in other answers.
When you don't want or can't use those patterns, and for primitive data types, there are three compelling reasons that I can think of why it's preferable to initialize the class attributes outside the constructor:
avoided repetition = if you have more than one constructor, or when you will need to add more, you won't have to repeat the initialization over and over in all the constructors bodies;
improved readability = you can easily tell with a glance which variables will have to be initialized from outside the class;
reduced lines of code = for every initialization done at the declaration there will be a line less in the constructor.
I take it is almost just a matter of taste, as long as initialization is simple and doesn't need any logic.
The constructor approach is a bit more fragile if you don't use an initializer block, because if you later on add a second constructor and forget to initialize b there, you'll get a null b only when using that last constructor.
See http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html for more details about initialization in Java (and for explanations on initalizer blocks and other not well known initialization features).
I've not seen the following in the replies:
A possible advantage of having the initialisation at the time of declaration might be with nowadays IDE's where you can very easily jump to the declaration of a variable (mostly
Ctrl-<hover_over_the_variable>-<left_mouse_click>) from anywhere in your code. You then immediately see the value of that variable. Otherwise, you have to "search" for the place where the initialisation is done (mostly: constructor).
This advantage is of course secondary to all other logical reasonings, but for some people that "feature" might be more important.
Both of the methods are acceptable. Note that in the latter case b=new B() may not get initialized if there is another constructor present. Think of initializer code outside constructor as a common constructor and the code is executed.
I think Example 2 is preferable. I think the best practice is to declare outside the constructor and initialize in the constructor.
The second is an example of lazy initialization. First one is more simple initialization, they are essentially same.
There is one more subtle reason to initialize outside the constructor that no one has mentioned before (very specific I must say). If you are using UML tools to generate class diagrams from the code (reverse engineering), most of the tools I believe will note the initialization of Example 1 and will transfer it to a diagram (if you prefer it to show the initial values, like I do). They will not take these initial values from Example 2. Again, this is a very specific reason - if you are working with UML tools, but once I learned that, I am trying to take all my default values outside of constructor unless, as was mentioned before, there is an issue of possible exception throwing or complicated logic.
The second option is preferable as allows to use different logic in ctors for class instantiation and use ctors chaining. E.g.
class A {
int b;
// secondary ctor
A(String b) {
this(Integer.valueOf(b));
}
// primary ctor
A(int b) {
this.b = b;
}
}
So the second options is more flexible.
It's quite different actually:
The declaration happens before construction. So say if one has initialized the variable (b in this case) at both the places, the constructor's initialization will replace the one done at the class level.
So declare variables at the class level, initialize them in the constructor.
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
Regarding the above,
String a = null;
null init could be avoided since anyway it's the default.
However, if you were to need another default value,
then, because of the uncontrolled initialization order,
I would fix as follow:
class MyClass extends FooClass
{
String a;
{
if( a==null ) a="my custom default value";
}
...
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)
I've seen some code as below in some example BlackBerry Java classes:
try
{
// stuff that will throw an exception
}
catch(final Exception e)
{
// deal with it
}
I presume the final is for performance. As per the title, since there's rarely (ever?) any reason to modify an Exception that's already been thrown, should they always be final?
If so, isn't this something that could be done by the compiler? Or is it done by the compiler and adding the final manually has no impact at all?
The Java Language Specification 11.2.2 makes a difference between final and not final exceptions:
A throw statement (§14.18) whose thrown expression has static type E and is not a final or effectively final exception parameter can throw E or any exception class that the thrown expression can throw.
[...]
A throw statement whose thrown expression is a final or effectively final exception parameter of a catch clause C can throw an exception class E iff:
E is an exception class that the try block of the try statement which declares C can throw; and
E is assignment compatible with any of C's catchable exception classes; and
E is not assignment compatible with any of the catchable exception classes of the catch clauses declared to the left of C in the same try statement.
Interestingly, JLS 14.20 also says:
In a uni-catch clause, an exception parameter that is not declared final (implicitly or explicitly) is considered effectively final if it never occurs within its scope as the left-hand operand of an assignment operator.
In other words, if you don't reassign the e of your catch statement (like e = new SomeOtherException();), it is implicitly declared final.
So I can only conclude that it does not make a difference, unless the exception is modified in the catch block and the only example I can come up with is:
public void method1() throws IOException {
try {
throw new IOException();
} catch (Exception e) { // e is not modified in catch => implicitly final
throw e; //compiles OK
}
}
//it works because method1 is semantically equivalent to method2:
public void method2() throws IOException {
try {
throw new IOException();
} catch (final Exception e) {
throw e;
}
}
public void method3() throws IOException {
try {
throw new IOException("1");
} catch (Exception e) {
e = new IOException("2"); //e modified: not implicitly final any more
throw e; //does not compile
}
}
I believe final is useful when the code which could use it is too long to easily read and understand. e.g. I would make fields final where possible to ensure they are assigned correctly in constructors and not modified anywhere in the class.
Using final for a catch clause is unlikely to help much as a) the value is guaranteed to be set b) the code using it should be short, c) its very rare to modify it anyway.
There is nothing stopping you from doing it however.
I'm not sure it's about performance, but more about convention. If you're using Eclipse, try to set a formatter that add the final keyword wherever it's possible, and reformat your source code with that formatter.
I've seen a couple of projects where everything what is not modified must be final (e.g. parameters, fields, local vars etc).
There's also a correspondent style check in PMD code analyzer, which verifies that everything what possible is declared as final.
I doubt final would really give any performance benefit because the exception instance is block local (Here is a really good answer explaining it https://stackoverflow.com/a/306966/492561).
So It merely serves as a explicit marker that says I will not modify.
Some times you may need to modify the exception to throw it back, may be edit the message to make it more clear at higher levels.
Essentially I would say that its a matter of preference, Some may like it others may not.
I have problem understanding the order in which initialization happens. this is the order I assumed:
*Once per
1. Static variable declaration
2. Static block
*Once per object
3. variable declaration
4. initialization block
5. constructor
but according to this code I am obviously wrong:
class SomethingWrongWithMe
{
{
b=0; //no. no error here.
int a = b; //Error: Cannot reference a field before it is defined.
}
int b = 0;
}
And the error would disappear if I do this:
class SomethingWrongWithMe
{
int b = 0;
{
b=0;
int a = b; //The error is gone.
}
}
I can't figure out why isn't there an error on
b=0;
The Java Language Specification (section 8.3.2.3) says you can use a variable on the left hand side of an expression, i.e. assign to it, before it is declared, but you cannot use it on the right hand side.
All variables are initialized to their default values, then explicit initializers and anonymous blocks are run in the order they are found in the source file. Finally the constructor is called.
Statics are only run once on the first use of a class.
The compile error appears to be a rule of Java rather than something that necessarily makes sense in every case.
Variable definitions are not done "before" blocks. They are both done at the same time, in the order that they are defined
class SomethingWrongWithMe {
{
b = debug("block 1");
}
int b = debug("define");
{
b = debug("block 2");
}
private int debug(String str) {
System.out.println(str);
return 0;
}
}
Output
block 1
define
block 2
First of all, your assumptions are more or less correct, except for the fact that declarations (with initialization, such as int b = 0) and instance initializer blocks are executed in the order they are written.
int b = 0; // executed first
{
b = 1; // executed second
}
int a = b; // executed third
Also note that the declaration i.e. int b is not executed. The declaration just declares the existence of the variable.
As for the error you got (or, rather the error you didn't get) I agree that it looks strange. I assume that the compiler deals with referencing a variable in an expression and assigning a value to it in different ways. When writing to a variable in an instance initializer, it just checks that the variable is there, while when reading from it, it requires it to be declared above the instance initializer block. I'll see if I can find a reference for that in the JLS.
I ran into this block of code today, and I don't know how it works. I know how to make anonymous classes, but I'm used to seeing a method signature and not just a pair of braces. Is the code between those braces put into a static block? Does it go into the constructor? Or is it something else altogether?
conext.checking(new Expectations() {
{ // <- what does this pair of braces do?
oneOf(alarm).getAttackAlarm(null);
}
});
It's an instance initializer that calls the code within the context of the created object.
This is equivalent to
Expectations exp = new Expectations();
exp.oneOf(alarm).getAttackAlarm(null);
conext.checking(exp)
Whoever wrote it might have thought he was being more efficient by not declaring a variable (not true) or that it was cleaner code (I disagree).
The primary place that these initializers are useful like this is when instantiating maps, ie:
Map map = new HashMap() {{
put("key1", "value1");
put("key2", "value2");
}};
which I think actually is slightly more readable.
It is an initializer block, but not necessarily a static initializer block. It is effectively a constructor for an anonymous inner class. You will typically see this "double-brace initialization" pattern to conveniently create and populate collections:
private final Collection<Integer> FIXED_COLLECTION = Collections.unmodifiableCollection(new HashSet<Integer>()
{ // first set of braces declares anonymous inner class
{ add(1); add(2); add(3); } // second set is initializer block
});
It's an instance initialiser (not a static initialiser).
Consider the definition of a class
public class Foo {
private int i = getDefaultValue();
private static int getDefaultValue() {
return 5;
}
}
The call to getDefaultValue() that initalises i is essentially a code block that runs each time an instance of Foo is constructed. The notation extends that function to allow more complex initialisation. E.g.
public class Foo {
private int i;
{
int z = 4 + 5;
i = z + getDefaultValue();
}
private static int getDefaultValue() {
return 5;
}
}
The manner with which it is used in JMock is a trick to give expectations the look of a closure construct.
What's happening ? The outer braces create a new anonymous class derived from Exception. The inner braces define an initialiser and sets the oneOf() etc.
Why do this ? It's a one-liner trick for constructing and initialising an instance of a class. e. you sometimes see something like this:
new HashSet<String>(){{ add("one"); add("two"); }}
to initialise the contents of a collection.
Downsides ? Because you're creating an anonymous class within the containing class, that anonymous class contains a this reference to the outer class implicitly. Not normally a problem, but it can cause issues if (say) you want to serialise a class that you've constructed like this.
It's an initializer block. I can't tell what it does without looking at the rest of the code.
The trick is to imagine "new Expectation()" replaced with "class Something extends Expectation".
Anynoymous inner classes don't have a constructor, so you can define a an instance initilizer like this i.e. the inner set of braces are the instance initializers.
new Expectations() {
{
oneOf(alarm).getAttackAlarm(null);
}
}
The primary motivation behind this, I believe, is to create a new name space, in which names defined in Expection can be referenced more easily.
For example, suppose java.lang.Math is not final,
new Math()
{{
double x = sin(23.65);
double y = log(x);
...
}};
It's almost as if we have something like
with names from Math
{
double x = sin(23.65);
double y = log(x);
...
}