Find out if constructor executed successfully or not - java

So i was playing around in java once again and while doing so, i ran into an interesting problem.
I was trying to write my self a little registration service. If an object of a certain type is instantiated via its constructor it would retrieve an id from my registration service and is added to the services list of objects.
Here is an example object
public class Test {
private final Long id;
public Test() {
this.id = TestRegistration.register(this);
throw new IllegalAccessError();
}
public Long getId() {
return this.id;
}
}
And here is an example service
public class TestRegistration {
private final static Map<Long, Test> registration = new HashMap<>();
protected final static long register(final Test pTest) {
if (pTest.getId() != null) {
throw new IllegalStateException();
}
long freeId = 0;
while (registration.containsKey(freeId)) {
freeId = freeId + 1;
}
registration.put(freeId, pTest);
return freeId;
}
protected final static Test get(final long pId) {
return registration.get(pId);
}
}
Now as you can see, the constructor of my class Test can't successfully execute at all since it always throws an IllegalAccessError. But the method register(...) of my TestRegistration class is called in the constructor before this error is thrown. And inside this method it is added to the registrations Map. So if i would run for example this code
public static void main(final String[] args) {
try {
final Test t = new Test();
} catch (final IllegalAccessError e) {
}
final Test t2 = TestRegistration.get(0);
System.out.println(t2);
}
My TestRegistration does in fact contain the object created when the constructor of my Test class was called and i can (here using variable t2) access it, even tho it wasn't successfully created in the first place.
My question is, can i somehow detect from within my TestRegistration class if the constructor of Test was executed successfully without any exceptions or other interruptions?
And before you ask why i throw this exception in the first place here is my answer. Test may have potential subclasses i don't know of yet but still will be registered in my TestRegistration class. But since i don't have influence on the structure of those subclasses i can't tell if their constructor will throw an exception or not.

It does not appear to be possible.
I've included the best I can gather from the JLS below.
As can be seen from that, the execution of the body of the constructor is the very last step in the creation of an object.
Thus I don't see any evidence to suggest that raising an exception would result in anything not happening which you could've checked to see whether the execution was successful (apart from the rest of the body of the constructor, obviously).
This may not seem particularly convincing, although I'm not convinced that you'd find anything more concrete than this (it is, after all, notoriously difficult to prove that something doesn't exist).
I would recommend putting the logic that modifies external data somewhere else.
It wouldn't be entirely unreasonable to require that a register method (either in the TestRegistration class, or in the object itself) be explicitly called after construction of an object.
It could also work to, instead of calling the constructors directly, have a class containing methods to return objects (which sounds a lot like the Factory Design Pattern), where you can then put this external modification logic.
From the JLS:
15.9.4. Run-Time Evaluation of Class Instance Creation Expressions
At run time, evaluation of a class instance creation expression is as follows.
First, if the class instance creation expression is a qualified class instance creation expression, the qualifying primary expression is evaluated. If the qualifying expression evaluates to null, a NullPointerException is raised, and the class instance creation expression completes abruptly. If the qualifying expression completes abruptly, the class instance creation expression completes abruptly for the same reason.
Next, space is allocated for the new class instance. If there is insufficient space to allocate the object, evaluation of the class instance creation expression completes abruptly by throwing an OutOfMemoryError.
The new object contains new instances of all the fields declared in the specified class type and all its superclasses. As each new field instance is created, it is initialized to its default value (§4.12.5).
Next, the actual arguments to the constructor are evaluated, left-to-right. If any of the argument evaluations completes abruptly, any argument expressions to its right are not evaluated, and the class instance creation expression completes abruptly for the same reason.
Next, the selected constructor of the specified class type is invoked. This results in invoking at least one constructor for each superclass of the class type. This process can be directed by explicit constructor invocation statements (§8.8) and is specified in detail in §12.5.
The value of a class instance creation expression is a reference to the newly created object of the specified class. Every time the expression is evaluated, a fresh object is created.
12.5. Creation of New Class Instances
...
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
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.
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass 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 4.
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.
Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.

Weather or not the constructor comples does not influence whether or not the object is created. All instance variables will be created the super() will still be called and memory will still be allocated.
In reality the exception will always be thrown, every object in your registration service will have thrown an exception. As children will have to call super() in order to be registered and following registration an exception is thrown.

Related

Cannot figure out code execution order [duplicate]

I am trying to piece together the process of Initialization and Instantiation in the JVM but the JLS is a little obtuse on a few details, so if anyone would mind clearing up some details it would be appreciated. This is what I have been able to figure out so far.
Initialization
Recursively Initialize static final variables of the class and it's interfaces that are compile time constants.
Back out of the recursion processing static blocks and static fields in textual order.
Instantiation
Recursively Initialize final instance variables of the class that are compile time constants.
Back out of the recursion processing non-static blocks and instance fields in textual order prepending them to the constructors as it returns.
Okay, so now for the questions.
are interfaces processed in order of declaration?
are interfaces processed in a separate recursive stack?
a) if yes, do interfaces get processed before or after superclasses?
b) if yes, am I correct in deducing that one or the others (Interface or Superclass) gets its non-compile-time constant fields initialized before the others compile-time constants.
What role does calls to the nondefault super() constructor play in this process?
Am I mistaken in any of my conclusions?
Am I missing any other key details?
It is important to distinguish between the initialization of a class, and initialization of an object.
Class Initialization
A class or interface is initialized upon first access, by assigning the compile time constant fields, then recursively initializing the superclass (if not already initialized), then processing the static initializers (which include the initializers for for the static fields that are not compile time constants).
As you have noticed, initialization of a class does not, by itself, trigger initialization of the interfaces it implements. Interfaces are therefore initialized when they are first accessed, typically by reading a field that is not a compile time constant. This access may occur during evaluation of an initializer, causing a recursive initialization.
It is also worth noting that initialization is not triggered by accessing fields that are compile time constants, as these are evaluated at compile time:
A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.
If such a field is static, then no reference to the field should be present in the code in a binary file, including the class or interface which declared the field. Such a field must always appear to have been initialized (§12.4.2); the default initial value for the field (if different than V) must never be observed.
If such a field is non-static, then no reference to the field should be present in the code in a binary file, except in the class containing the field. (It will be a class rather than an interface, since an interface has only static fields.) The class should have code to set the field's value to V during instance creation (§12.5).
Object Initialization
An object is initialized whenever a new object is created, typically by evaluation of a class instance creation expression. This proceeds as follows:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
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.
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass 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 4.
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.
Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.
As we can see in step 3, the presence of an explicit call to the super constructor simply changes which super class constructor is invoked.
Following is an example that print the order of each step during object creation.
InstanceCreateStepTest.java:
import javax.annotation.PostConstruct;
/**
* Test steps of instance creation.
*
* #author eric
* #date Jan 7, 2018 3:31:12 AM
*/
public class InstanceCreateStepTest {
public static void main(String[] args) {
new Sub().hello();
System.out.printf("%s\n", "------------");
new Sub().hello();
}
}
class Base {
static {
System.out.printf("%s - %s - %s\n", "base", "static", "block");
}
{
System.out.printf("%s - %s - %s\n", "base", "instance", "block");
}
public Base() {
System.out.printf("%s - %s\n", "base", "constructor");
}
#PostConstruct
public void init() {
System.out.printf("%s - %s\n", "base", "PostConstruct");
}
public void hello() {
System.out.printf("%s - %s\n", "base", "method");
}
}
class Sub extends Base {
static {
System.out.printf("%s - %s - %s\n", "sub", "static", "block");
}
{
System.out.printf("%s - %s - %s\n", "sub", "instance", "block");
}
public Sub() {
System.out.printf("%s - %s\n", "sub", "constructor");
}
#PostConstruct
public void init() {
System.out.printf("%s - %s\n", "sub", "PostConstruct");
}
#Override
public void hello() {
// super.hello();
System.out.printf("%s - %s\n", "sub", "method");
}
}
Execution:
Just invoke the main method, and then check the output.
Tips:
The methods marked by #PostConstruct won't be invoked, unless you invoke it inside some container, like Spring-boot, since it depends on those containers to implement annotation like #PostConstruct.

How does constructor return if it doesn't have any return type?

This seems to be quite a confusing question. Per the definition, I understand that constructor is a special type of method used to initialize the state of an object and/or assign values to instance variables.
Also someone in Stack Overflow mentioned that constructor returns an object (instance) of a class, as opposed to what a normal method does/returns?
Despite going through lots of tutorials and reference materials, I couldn't find a concrete reason as to how constructor is able to return a value without the presence of a return statement.
I'm curious to find out the internal working of the entire process.
Constructors don't return anything. A constructor simply initializes an instance.
A new instance creation expression
new SomeExample();
produces a reference to a new instance of the specified class
A new class instance is explicitly created when evaluation of a class
instance creation expression (§15.9) causes a class to be
instantiated.
and invokes the corresponding constructor to initialize the created instance
Just before a reference to the newly created object is returned as the
result, the indicated constructor is processed to initialize the new
object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
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.
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If
this constructor is for a class other than Object, then this
constructor will begin with an explicit or implicit invocation of a
superclass constructor (using super). Evaluate the arguments and
process that superclass 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 4.
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.
Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the
same reason. Otherwise, this procedure completes normally.
It gives the JVM the 'return' opcode:
'return' returns to the calling method:
http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
Code for a default constructor:
aload_0
invokespecial #1; //Method java/lang/Object
return
A Java constructor does not return anything. A constructor simply initializes a new instance of an object of a specific class. Sometimes constructors will have System.out.Println("text") which may lead you to think it returns something, but you can have that statement in any method that doesn't have a return type.
In bytecode
Test1 t1 = new Test1();
looks as follows
NEW test/Test1 //create an uninitized instance of Test1
DUP
NVOKESPECIAL test/Test1.<init> ()V // call construcctor
STORE 1 // save reference to created instance in local var
and this is constructor, void method in fact with special name <init>
public <init>()V //V means no return value, void
L0
LINENUMBER 3 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V // call super constructor
RETURN

Are statements under curly braces load first?

I know static contents are loaded first in the memory, but why is 'IT' printed before 'CT' when I haven't mentioned it as static?
class Person
{
Person()
{
System.out.print(" CP");
}
static
{
System.out.print("SP");
}
}
class Teacher extends Person
{
Teacher()
{
System.out.print(" CT");
}
{
System.out.print(" IT");
}
}
public class StaticTest
{
public static void main(String[] args)
{
Person p = new Teacher();
}
}
Initializer blocks such as {System.out.print(" IT");} are executed before the constructor. Actually, they are copied to the beginning of each constructor.
Initializing Instance Members
Normally, you would put code to initialize an instance variable in a
constructor. There are two alternatives to using a constructor to
initialize instance variables: initializer blocks and final methods.
Initializer blocks for instance variables look just like static
initializer blocks, but without the static keyword:
{
// whatever code is needed for initialization goes here
}
The Java compiler copies initializer blocks into every constructor.
Therefore, this approach can be used to share a block of code between
multiple constructors.
(Source)
And to be more exact, here's the initialization order as described in the JLS :
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
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.
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass 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 4.
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.
Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.
Notice that the instance initializers are executed in step 4, prior to the body of the constructor (step 5).

How exactly does the 'new' keyword and constructors work

Ok, so i'm study for my first java certification and i can't quite understand exactly what happens underneath the hood when an object is created, some explanations that iv'e read states that the constructor returns the reference to an object which is a source of confusion for me because from my understanding this is done by the new keyword. My questions are:
Where does the reference to an object actually come from, the 'new' keyword or the constructor?
When an object is created using the 'new' keyword, does it implicitly pass this object to the constructor?
When an object is created using the 'new' keyword, is it just a java Object until it is passed to the constructor eg. Person me = new Person(); Is this object associated with the class person as soon as it is created, or only after it has been passed to the constructor
The entire expression of new Constructor(arguments) is considered one instance-creation expression, and is not meaningful as a separate new keyword and constructor call.
The JLS, 15.9.4 describes the actual creation of the instance, which is comprised of three steps:
Qualifying the expression (not applicable when using new)
Allocating space for the instance in memory, and setting fields to default values.
Evaluating arguments for the constructor, and calling the constructor.
First, if the class instance creation expression is a qualified class
instance creation expression, the qualifying primary expression is
evaluated. If the qualifying expression evaluates to null, a
NullPointerException is raised, and the class instance creation
expression completes abruptly. If the qualifying expression completes
abruptly, the class instance creation expression completes abruptly
for the same reason.
Next, space is allocated for the new class instance. If there is
insufficient space to allocate the object, evaluation of the class
instance creation expression completes abruptly by throwing an
OutOfMemoryError.
The new object contains new instances of all the fields declared in
the specified class type and all its superclasses. As each new field
instance is created, it is initialized to its default value (§4.12.5).
Next, the actual arguments to the constructor are evaluated,
left-to-right. If any of the argument evaluations completes abruptly,
any argument expressions to its right are not evaluated, and the class
instance creation expression completes abruptly for the same reason.
Next, the selected constructor of the specified class type is invoked.
This results in invoking at least one constructor for each superclass
of the class type. This process can be directed by explicit
constructor invocation statements (§8.8) and is specified in detail in
§12.5.
The value of a class instance creation expression is a reference to
the newly created object of the specified class. Every time the
expression is evaluated, a fresh object is created.
Yes, as bytecode this all turns into one invokespecial call with the new instance at the bottom of the stack of parameters passed. Please see the bottom of this answer. Semantically, however, the constructor doesn't get the new instance "passed" to it, but that instance is made available as this in Java source code.
This question doesn't make semantic sense, as the object doesn't "exist" to the outside world until the constructor returns. If the construction terminates abruptly, the object is not actually created and available. However, in memory on an OpenJDK JVM at least, the type of the object as well as any types that it extends/implements are written to an in-memory header. This is not guaranteed for all implementations, however.
Disassembly:
I compiled and disassembled:
class Test{
public static void main(String args[]){
Integer s = new Integer(2);
}
}
This is the result:
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Integer
3: dup
4: iconst_2
5: invokespecial #3 // Method java/lang/Integer."<init>":(I)V
8: astore_1
9: return
As you can see, first the object is allocated using new, which fills in all fields as defaults. It's duplicated, so the stack looks like:
our new Integer
our new Integer
The constant value that I passed to the constructor is then pushed:
2
our new Integer
our new Integer
invokespecial occurs, which passes the top two stack elements--the new instance, and the constructor's parameter.

Inline initialization blocks in java

I have a class
public class MyMain{
public static void main(String... arg){
Temp t = new Temp(){
{
System.out.println(" instance initialize");
}
};
}
}
class Temp{
int i;
{
i=9;
System.out.println("Static"+i);
}
Temp(){
System.out.println("Temp const "+i);
}
}
When i execute the main method the output comes:
Static9
Temp const 9
instance initialize
Ideally, the blocks are executed before the constructor, but the inline initialization block is called after the Constructor. Why?
You're creating a subclass of Temp. For each class, any instance initializers are executed before the constructor body - but the superclass goes through initialization before the subclass initialization. So the execution flow is:
Initializers in Object
Constructor body in Object
Initializers in Temp
Constructor body in Temp
Initializers in anonymous class
Constructor body in anonymous class (none)
I would strongly advise you to refactor any code which looked like this anyway - aim for clarity rather than cleverness.
JLS 12.5 spells out the order in which things happen during construction (emphasis mine):
Just before a reference to the newly created object is returned as the
result, the indicated constructor is processed to initialize the new
object using the following procedure:
(3) This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If
this constructor is for a class other than Object, then this
constructor will begin with an explicit or implicit invocation of a
superclass constructor (using super). Evaluate the arguments and
process that superclass 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 4.
(4) 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.
(5) Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the
same reason. Otherwise, this procedure completes normally.
To summarize, superclass constructors (step 3) are executed before instance initializers (step 4). Both are executed before "the rest of the body of this constructor" (which you don't have in your example).
The inline initialisation block is called after the constructor of the base class of the anonymous class you are instancing at the moment and before the empty implicit constructor of the anonymous class itself.
What you are actually creating is not a Temp class instance, but an instance of some anonimous class, that inherits from Temp.
Thus, at first, the Temp initializers are called (anonimous block inside Temp and its construstor) and initializers in anonimous class are called afterwards.
In your code
Temp t = new Temp(){
{
System.out.println(" instance initialize");
}
};
you are creating object of anonymous class which extends Temp class.
Creating object of Subclass:
initialize block from Superclass
constructor of Superclass
initialize block from Subclass
constructor of Subclass
Point 1: To be clear, you have two instance initializers: one in the Temp class and one in the anonymous inner class created in the main() method that is a subclass of Temp.
Point 2: Instance initializers aren't actually run before constructors. Per the JLS, they're run during a constructor, after delegating to the super constructor and before initializing instance fields and completing the constructor.
Point 3: In your code, each initializer is correctly executed at its appropriate time. I think you're expecting the second one to execute at the same time as the first one, but that would be incorrect because as pointed out in Point 1, they're initializers for two different classes.
Point 4: You may also be confused between static initializers and instance initializers. They're two distinct things.
The object must be in memory first before anything else can be done to it. The object is constructed in memory and then your console prints happen.

Categories