Why can't I do assignment outside a method? - java

If I try to assign a value to a variable in a class, but outside a method I get an error.
class one{
Integer b;
b=Integer.valueOf(2);
}
but, if I initialize it during the creation, it works.
class one{
Integer b=Integer.valueOf(2);
}
Inside a method, it works in both cases.

you need to do
class one{
Integer b;
{
b=Integer.valueOf(2);
}
}
as statements have to appear in a block of code.
In this case, the block is an initailiser block which is added to every constructor (or the default constructor in this case) It is run after any call to super() and before the main block of code in any constructor.
BTW: You can have a static initialiser block with static { } which is called when the class is initialised.
e.g.
class one{
static final Integer b;
static {
b=Integer.valueOf(2);
}
}

Because the assignments are statements and statements are allowed only inside blocks of code(methods, constructors, static initializers, etc.)
Outside of these only declarations are allowed.
This :
class one{
Integer b=Integer.valueOf(2);
}
is a declaration with an initializer. That's why is accepted

A more general answer would be that the class body is about declarations, not statements. There is a special provision for statements occuring in class body, but they have to be marked explicitly as either class initializers or instance initializers.

In Java, when defining a class, you can define variables with default values and add methods. Any executable code (such as assignments) MUST be contained in a method.

This is the way java works, you cannot add non-declaration code (sorry i don't know the correct term) inside the class, that code should be inside methods.

I think terminology-wise, couple of other answers are slightly off. Declarations are also statements. In fact, they are called "declaration statements", which are one of the three kinds of statements. An assignment statement is one form of "expression statement" and can be used only in constructs such as methods, constructors, and initializers. Check out the Statements section in this Oracle's tutorial link.

Methods have the responsibility to perform mutations on the member variables. If the member variable needs to be initialized, java provides a way to do it during construction, class definition (latter case). But the mutation cannot be performed during definition.(former case). It is usually done at the method level.
Objects are meant to hold the state, while methods are meant to operate on that state.

Related

Cannot access FileChooser methods [duplicate]

When I write the following code in Eclipse:
public class MyClass {
System.currentTimeMillis();
}
I get this compile error:
Syntax error on token "currentTimeMillis", Identifier expected after this token
It works if I change that statement to an assignment statement:
long time = System.currentTimeMillis();
Of course, it doesn't cause errors if placed inside a method body or within blocks inside the class body.
Why is this? Is there some compiler level rule that says that only assignment statements or declarations should be present inside the class body?
The class body can only contain declarations.
Specifically, § 8.1.6 of the JLS defines the class body like this:
A class body may contain declarations of members of the class, that is, fields (§8.3), classes (§8.5), interfaces (§8.5) and methods (§8.4). A class body may also contain instance initializers (§8.6), static initializers (§8.7), and declarations of constructors (§8.8) for the class.
ClassBody:
{ ClassBodyDeclarationsopt }
ClassBodyDeclarations:
ClassBodyDeclaration
ClassBodyDeclarations ClassBodyDeclaration
ClassBodyDeclaration:
ClassMemberDeclaration
InstanceInitializer
StaticInitializer
ConstructorDeclaration
ClassMemberDeclaration:
FieldDeclaration
MethodDeclaration
ClassDeclaration
InterfaceDeclaration
;
As you can see, there are no statements in there anyway, so a class body may not directly contain a statement.
If you think about it, it makes sense: at which point should that code be executed? There is no context to tell you about that, so it makes no sense.
This is illegal. In the class body you can have only: blocks, fields, constructors, methods and classes
Yours is neither. And what would you expect it to do anyway? If you want it to be executed when the class is instantiated, then place it in a block:
{
System.currentTimeMillis();
}
Try this way:
public class MyClass {
static {
System.currentTimeMillis();
}
}
If you call System.currentTimeMillis() inside a static statement it works.
The static block will be called when the class "MyClass" is loaded by the class loader.
Is there some compiler level rule that says that only assignment statements or declarations should be present inside the class body?
In a word: yes. At the class body level you can have instance and static member variable declarations, method declarations, nested classes, object initialization blocks, static initialization blocks, and comments. That's it, by definition.
The "compiler level rules" for a language are called its grammar.
You need to call your code from inside a method, not just on its own like that. E.g.
public class MyClass {
public static void main(String[] args)
{
System.currentTimeMillis();
}
}
The above still won't do anything, but it's legal :-)
You dont get the error with the line
long time = System.currentTimeMillis();
because you are specifying a private variable inside the class (long time) and setting them to a default value (System.currentTimeMillis()) so when you make a new instance of the class MyClass, the variable is being instantiated.
calling only System.currentTimeMillis() just has nosense, because you arent doing nothin' (neither having a context or assigning the value to a private variable)
Is there some compiler level rule that
says that only assignment statements
or declarations should be present
inside the class body?
Yes. More specifically, the syntactic rules of programming languages are usually defined as a formal grammar that specifies how syntactically correct programs are formed. In this case, the Java language specification says:
ClassBody:
{ ClassBodyDeclarationsopt }
ClassBodyDeclarations:
ClassBodyDeclaration
ClassBodyDeclarations ClassBodyDeclaration
ClassBodyDeclaration:
ClassMemberDeclaration
InstanceInitializer
StaticInitializer
ConstructorDeclaration
Since a static method call is not one of ClassMemberDeclaration, InstanceInitializer, StaticInitializer and ConstructorDeclaration, it's not allowed to be present directly inside a class body.
long time = System.currentTimeMillis();
is an instance variable, which gets initalized to the current time when the enclosing Object is created. Valid.
System.currentTimeMillis();
is a statement on its own. Invalid, outwith a constructor, method, static iniatilizer etc.

Java - passing instance variables to this() method

I was learning about using this() to call an overloaded constructor and came across this restriction:
You can not use any instance variable of the constructor's class in a call
to this()
For example:
class Test{
int x;
public Test() {
this(x); //Does not compile
}
public Test(int y) {}
void method1() {
method2(x); //OK
}
void method2(int y) {}
}
I know that no need to pass an instance field to a constructor since it's visible by default. However, why is the same restriction not applied to instance methods?
There is one other requirement in Java: constructor calls (using this() must be performed first within any constructor. The constructors will initialize the object.
After that the instance fields are initialized after these initial calls. So as the field values are now well defined, you can use them for anything including calling other methods.
However, before the initial constructor calls, the fields are in an undefined state and cannot be used as argument for other constructor calls.
For these kind of things you need to look in the JLS:
If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.
Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.
So the instance variables are only initialized after the constructor calls. This makes sense, because it would be strange to first assign it the default value (zero or null) and then assign it another value from within a constructor.
The constructor constructs the instance. So we shouldn't expect the instance variable x to be initialized at the time the constructor starts.
On the other hand, an instance method can already access instance variables. There is no reason to forbid passing them as a parameter into another instance method.
However, when we start to think about it a bit further, that restriction on the constructor doesn't make that much sense anymore. We are able to access instance variables there as well, so why shouldn't we be able to pass it a parameter to another constructor?
So a better question to ask is: Why can't we pass an instance variable to call an overload of our constructor from within our constructor?
And this question has been beautifully answered. It could even be considered a duplicate (but since that pretext is neccessary to understand why, I wrote an answer instead of simply flagging).
The instance fields that are declared and initialized in the class body outside of the constructor, like your int x; are assigned after the call to the overloaded constructor.
You can compare that to the other restriction we have about calling constructor overloads: We can only do so in the first line of our constructor. Right at the start. And then, the variables are not yet initialized. But they are initialized right before the first non-constructor-call instruction.
Tangential information to why this other restriction is a thing can be found here and there:
Because the JLS says so. Could the JLS be changed in a compatible manner to allow it? Yup.
Historically, this() or super() must be first in a constructor. This
restriction was never popular, and perceived as arbitrary. There were
a number of subtle reasons, including the verification of
invokespecial, that contributed to this restriction. Over the years,
we've addressed these at the VM level, to the point where it becomes
practical to consider lifting this restriction, not just for records,
but for all constructors.
You should be educating the class order initialization f.e: https://www.baeldung.com/java-initialization
The int x field is not initialized when the class constructor is called. You can set (initialize) `int x 'in your constructor, but not call it.
I don't know why you have to follow this way, but you can use the static field:
class Test{
static int x;
public Test() {
this(x); //Does not compile
}
public Test(int y) {}
void method1() {
method2(x); //OK
}
void method2(int y) {}
}
You can also initialize a static field in the line where it is called,
static int x =4/2;
or in static block:
static int x;
static {
x = 4/2;
}

Processing - Return type for method is missing [duplicate]

If I try to assign a value to a variable in a class, but outside a method I get an error.
class one{
Integer b;
b=Integer.valueOf(2);
}
but, if I initialize it during the creation, it works.
class one{
Integer b=Integer.valueOf(2);
}
Inside a method, it works in both cases.
you need to do
class one{
Integer b;
{
b=Integer.valueOf(2);
}
}
as statements have to appear in a block of code.
In this case, the block is an initailiser block which is added to every constructor (or the default constructor in this case) It is run after any call to super() and before the main block of code in any constructor.
BTW: You can have a static initialiser block with static { } which is called when the class is initialised.
e.g.
class one{
static final Integer b;
static {
b=Integer.valueOf(2);
}
}
Because the assignments are statements and statements are allowed only inside blocks of code(methods, constructors, static initializers, etc.)
Outside of these only declarations are allowed.
This :
class one{
Integer b=Integer.valueOf(2);
}
is a declaration with an initializer. That's why is accepted
A more general answer would be that the class body is about declarations, not statements. There is special provision for statements occuring in class body, but they have to be marked explicitly as either class initializers or instance initializers.
In Java, when defining a class, you can define variables with default values and add methods. Any executable code (such as assignments) MUST be contained in a method.
This is the way java works, you cannot add non-declaration code (sorry i don't know the correct term) inside the class, that code should be inside methods.
I think terminology-wise, couple of other answers are slightly off. Declarations are also statements. In fact, they are called "declaration statements", which are one of the three kinds of statements. An assignment statement is one form of "expression statement" and can be used only in constructs such as methods, constructors, and initializers. Check out the Statements section in this Oracle's tutorial link.
Methods have the responsibility to perform mutations on the member variables. If the member variable needs to be initialized, java provides a way to do it during construction, class definition (latter case). But the mutation cannot be performed during definition.(former case). It is usually done at the method level.
Objects are meant to hold the state, while methods are meant to operate on that state.

Difference between initialization at declaration and initialization in constructor [duplicate]

This question already has answers here:
Initialize class fields in constructor or at declaration?
(16 answers)
Closed 10 years ago.
What is the difference between the following two, and which is more preferable??
public class foo {
int i = 2;
}
public class foo {
int i;
foo() {
i = 2;
}
}
In your example, there is no difference in behavioural semantics. In Java, all instance field initializers (and instance blocks) are executed after superclass initialization, and before the body of the constructor; see JLS 12.5.
The difference lies in code readability and (in other examples) avoiding repetitious coding and fragility1. These need to be assessed on a case-by-case basis.
It is also worth noting that there are some cases where you have to initialize in the constructor; i.e. when the initialization depends on a constructor parameter.
1 - The repetitiousness and fragility issues are flip-sides of the same thing. If you have multiple constructors, the "initialize in constructor" approach tends to lead to repetition. And if you add extra fields, you might to add the initialization to all relevant constructors; i.e. fragility.
If you have two or more constructors and intialization value differs in each of them, then you should use constructor initialization as there is no way to do the same with member initialization...
however if you have just one constructor...you can use member initialization for better code clarity..
In particular this case there is no difference in these two variants. First variant is more preferable, because initializations of fields inside constructor, as usual, use external values from constructor arguments.
First of all I think the second example should look like this:
public class foo{
int i;
foo(){
i = 0;
}
}
Otherwise i is just a local variable in the C'tor scope.
Second, the first example shows initialization which is called before the class C'tor is invoked. this is good if you want this to happen no matter what C'tor is used.
It also enables you to declare i as readonly.
In your first example, i is an instance variable of class foo (better name would be Foo). It's initialised at class loading.
In your second example, i is also an instance varaible but in this case initialised in the foo() constructor.
There is no real difference here, and especially with primitives.
However, in a multi-threaded environment, if you do intend to initialise your ivars in your constructor, and those ivars are non-primitive, you need to avoid the risk of exposing a partially constructed object. The reason for this is that constructors aren't synchronised and can't have the synchronised keyword applied but then two threads can't be constructing the same object.
So, to avoid this, you should never expose this in your constructor. One way of doing so is to call non-final methods. Doing so, say calling an abstract method, allows some unknown code to do something with your unfinished object. Obviously, this can't be done if you initialise in your declaration.
p.s. I thought there was something on this in Effective Java but couldn't find anything.

java class member initialisation

I am a bit ashamed to ask that, being a Java programmer for years, but here goes:
Is there a difference between allocating objects during construction, and doing so directly when declaring the relevant field? That is, is there a difference between the following two:
public class MyClass{
MyObj obj=new MyObj();
}
AND
public class MyClass{
MyObj obj;
public MyClass() {
obj=new MyObj();
}
}
Of course, I assume this specific init's do not rely on outside parameters.
instance variable initialization done before constructor call
Its not good to do.
You can restrict user from call of const. if you want to perform certain operation before initialization.
Best Practice:
Don't initialize with the default values in declaration (null, false, 0, 0.0...).
Prefer initialization in declaration if you don't have a constructor parameter that changes the value of the field.
If the value of the field changes because of a constructor parameter put the >initialization in the constructors.
Be consistent in your practice. (the most important rule)
from here
No, there isn't. Except that if you add multiple constructors you'll have duplicate code.
An alternative is to use an initializer block
{
var = 1;
}
Reference: Initializing Fields

Categories