The javadoc for the set method of Fieldclass clearly states that ExceptionInInitializerError may occur if the initialization provoked by this method fails.
I was wondering that Classes get lazily initialized when they are referenced or when we use Class.forName("binary name",true,ClassLoader) .if initialization of class does not fail,then class variables have been initialized according to the value assigned in the declaration or as in static constructor.Once a field has been initliazed ,can it explicity throw ExceptionInInitializerError when called by the Field's class set method??
Field#set(Object, Object) can be used to set static fields. If you try to set the field of an unitialized class, the JVM will first try to initialize the class. If a failure occurs, then set will throw a ExceptionInInitializerError. See the example below:
public class Example {
public static void main(String[] args) throws Exception {
Field field = Fail.class.getDeclaredField("number");
field.set(null, 42); // Fail class isn't initialized at this point
}
}
class Fail {
static int number;
static {
boolean val = true;
if (val)
throw new RuntimeException(); // causes initialization to end with an exception
}
}
Related
I have a class looks like this
class Some {
private enum Inner {
}
}
And I'm trying to find the Inner class in a initialization block of my test class.
class SomeTest {
private static final Class<?> INNER_CLASS;
{
for (final Class<?> declaredClass: Some.class.getDeclaredClasses()) {
if (declaredClass.getSimpleName().equals("Inner")) {
INNER_CLASS = declaredClass;
// Variable `INNER_CLASS` might be assigned in loop
// break? return?
}
}
throw new ExceptionInitializerError("failed to find Inner.class");
}
}
The compiler doesn't like this and I couldn't find any better way.
How can I solve this? Is there any good pattern for this?
static and instance initialization block cannot throw checked exceptions as there is no way to declare that those blocks throws these execeptions. Change ExceptionInitializerError to RuntimeException (or any subclass) and wrap your code in try-catch
Besides here, you are not returning nor breaking thus you always throw exception.
As for "breaking out" well simply yo dont. You have to write that block as it would be body of void method but with the restriction that you cannot use return anywhere.
There are a few problems with your code:
You have the exception name incorrect. The exception you are trying to throw is called ExceptionInInitializerError not ExceptionInitializerError. That is one reason why it won't compile.
Never1 throw Error or subclasses of Error.
If you need to throw an unchecked exception, throw RuntimeException. Or better still, pick something more specific or define and use your own custom (unchecked) exception class.
This should (probably) be a static initializer block, not a plain (instance) initializer. You want this code to be executed once ... not every time a SomeTest instance is created.
Bailing out of a static initializer block is something you want to avoid. It basically leaves you with a dead application ... because the enclosing class and any classes that depend on it become uninitializable.
Having said that, the following might be a more appropriate structure:
static {
BlahType tmp = null;
label: {
for (...) {
if (...) {
tmp = ...;
break label;
}
}
throw new SomeException(...);
}
FINAL_VAR = tmp;
}
Note that we need to do the final assignment to FINAL_VAR in a way that ensures that it is definitely assigned. (My guess is that is a second reason you were getting compilation errors.)
And a more natural way to write the above would be:
static {
BlahType tmp = null;
for (...) {
if (...) {
tmp = ...;
break;
}
}
if (tmp == null) {
throw new SomeException(...);
}
FINAL_VAR = tmp;
}
1 - Maybe a bit too strong. I would say that throwing AssertionError is OK ... assuming that you intend for it never be caught / recovered from. In this case, recovery is moot anyway.
Use intermediate variable before final assignment.
class SomeTest {
private static final Class<?> INNER_CLASS;
static {
Class<?> innerClass = null;
for (final Class<?> declaredClass: Some.class.getDeclaredClasses()) {
if (declaredClass.getSimpleName().equals("Inner")) {
innerClass = declaredClass;
}
}
if (innerClass == null) {
throw new ExceptionInitializerError("failed to find Inner.class");
}
INNER_CLASS = innerClass;
}
}
There are couple of issues:
The exception is always thrown
You are assigning to a final variable in a loop
The initialization block is not static and assigning to a static final variable
Check this out:
class SomeTest {
private static final Class<?> INNER_CLASS;
static {
Class<?> foundClass = null;
for (final Class<?> declaredClass : Some.class.getDeclaredClasses()) {
if (declaredClass.getSimpleName().equals("Inner")) {
foundClass = declaredClass;
// Variable `INNER_CLASS` might be assigned in loop
// break? return?
}
}
INNER_CLASS = foundClass;
// throw new Exception("failed to find Inner.class");
}
}
I have set a private static properties object to load in some configuration for my factory class in the constructor of factory class.
public class BussinessServiceFactory {
private static final BussinessServiceFactory factory = new BussinessServiceFactory();
public static BussinessServiceFactory createBussinessServiceFactory(){
return factory;
}
private BussinessServiceFactory(){
InputStream in = BussinessServiceFactory.class.getClassLoader().getResourceAsStream("factory/bussinessservice.properties");
try {
bsConfig.load(in);
} catch (IOException exception) {
// TODO Auto-generated catch block
throw new RuntimeException(exception);
}
}
private static Properties bsConfig = new Properties();
public <T> T createBussinessService(Class<T> clazz){
try {
String clazzName = clazz.getSimpleName();
String name = bsConfig.getProperty(clazzName);
return (T) Class.forName(name).newInstance();
} catch (InstantiationException | IllegalAccessException
| ClassNotFoundException exception) {
throw new RuntimeException(exception);
}
}
}
However, when I initialize the class, it throws NullPointerException.
java.lang.NullPointerException
at factory.BussinessServiceFactory.<init>(BussinessServiceFactory.java:15)
at factory.BussinessServiceFactory.<clinit>(BussinessServiceFactory.java:8)
... 24 more
Then if I change the properties object into non-static object, the problem is solved. But I am still confused by the reason why would this happen and how it could be solved in this way.
static initializers are done topdown. So the static field factory is initialized when the class BussinessServiceFactory is loaded. This static initializer calls the constructor for BussinessServiceFactory, and so therefore, eventually, loads a reference to the static field bsConfig. This field is not yet initialized at this point, since we are still in the static initializer block for the factory field. Hence, the NullPointerException.
Fix this either 1) reordering the bsConfig field to be above the factory field, or better yet, don't have this interfield dependency by making the bsConfig field an instance field (which is what you did to fix it, and i believe is the best way to fix such an issue).
see http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4 for details about order of static initialization.
addendum:
the stacktrace reveals the source of your problem. The clinit in the stacktrace stands for class init, and therefore, you can tell that the issue is loading of a class.
public class InstanceBuilder {
private static final InstanceBuilder INSTANCE = new InstanceBuilder();
private static String name = null;
private InstanceBuilder() {
System.out.println("Setting cons()");
name = "Testing";
}
public static String getName() {
return name;
}
}
public class Driver {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("value is " + InstanceBuilder.getName());
}
}
Output:
Setting cons()
value is null
Why does it print value as null even though I have set the static variable in constructor and it is called as expected. If I try to print in constructor, it is printing Testing, but if I call from public static method, it is null. I know if I change it to INSTANCE.name, it works.
But I want to understand why it is not working if I directly access static variable since same copy should be shared.
What I am missing here?
Because the value of name is getting modified after the constructor invocation as per the declaration order.
Lets see what is happening:
1) When you call InstanceBuilder.getName(), InstanceBuilder class is getting loaded. As part of that process INSTANCE and name instance variables are getting initialized.
2) While initializing INSTANCE,
private static final InstanceBuilder INSTANCE = new InstanceBuilder();
constructor of InstanceBuilder class is getting invoked & Setting cons() statement is getting printed and name variable is initialized with Testing.
3) Next name is again getting re-initialized with null due to the below statement
private static String name = null;
so when the method call returns to Driver class, value of name is null and null is getting printed. So even though name is declared as static, static has no role in that context.
Note:
Check the below link on the order of which class members should be declared
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-141855.html#1852
Here value is null because static initialization occurs as its declare in order,
So First your
`private static final InstanceBuilder INSTANCE = new InstanceBuilder();`
code execute and assign value to "testing", then your
`private static String name = null;`
code exceute and override value to null(as static variable have coppy per class only), so final value will be null.
So here this behavior is just beacuse of order of execution of static variable
Does calling a static method on a class in Java trigger the static initalization blocks to get executed?
Empirically, I'd say no. I have something like this:
public class Country {
static {
init();
List<Country> countries = DataSource.read(...); // get from a DAO
addCountries(countries);
}
private static Map<String, Country> allCountries = null;
private static void init() {
allCountries = new HashMap<String, Country>();
}
private static void addCountries(List<Country> countries) {
for (Country country : countries) {
if ((country.getISO() != null) && (country.getISO().length() > 0)) {
allCountries.put(country.getISO(), country);
}
}
}
public static Country findByISO(String cc) {
return allCountries.get(cc);
}
}
In the code using the class, I do something like:
Country country = Country.findByISO("RO");
The problem is that I get a NullPointerException because the map (allCountries) is not initialized. If I set up breakpoints in the static block I can see the map getting populated correctly, but it's as if the static method has no knowledge of the initializer being executed.
Can anyone explain this behavior?
Update: I've added more detail to the code. It's still not 1:1 (there are several maps in there and more logic), but I've explicitly looked at the declarations/references of allCountries and they are as listed above.
You can see the full initialization code here.
Update #2: I tried to simplify the code as much as possible and wrote it down on the fly. The actual code had the static variable declaration after the initializer. That caused it to reset the reference, as Jon pointed out in the answer below.
I modified the code in my post to reflect this, so it's clearer for people who find the question. Sorry about the confusion everyone. I was just trying to make everyone's life easier :).
Thanks for your answers!
Does calling a static method on a class in Java trigger the static initalization blocks to get executed?
Empirically, I'd say no.
You're wrong.
From the JLS section 8.7:
A static initializer declared in a class is executed when the class is initialized (§12.4.2). Together with any field initializers for class variables (§8.3.2), static initializers may be used to initialize the class variables of the class.
Section 12.4.1 of the JLS states:
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
T is a class and an instance of T is created.
T is a class and a static method declared by T is invoked.
A static field declared by T is assigned.
A static field declared by T is used and the field is not a constant variable (§4.12.4).
T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
This is easily shown:
class Foo {
static int x = 0;
static {
x = 10;
}
static int getX() {
return x;
}
}
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(Foo.getX()); // Prints 10
}
}
Your problem is in some part of the code that you didn't show us. My guess is that you're actually declaring a local variable, like this:
static {
Map<String, Country> allCountries = new HashMap<String, Country>();
// Add entries to the map
}
That hides the static variable, leaving the static variable null. If this is the case, just change it to an assignment instead of a declaration:
static {
allCountries = new HashMap<String, Country>();
// Add entries to the map
}
EDIT: One point worth noting - although you've got init() as the very first line of your static initializer, if you're actually doing anything else before then (possibly in other variable initializers) which calls out to another class, and that class calls back into your Country class, then that code will be executed while allCountries is still null.
EDIT: Okay, now we can see your real code, I've found the problem. Your post code has this:
private static Map<String, Country> allCountries;
static {
...
}
But your real code has this:
static {
...
}
private static Collection<Country> allCountries = null;
There are two important differences here:
The variable declaration occurs after the static initializer block
The variable declaration includes an explicit assignment to null
The combination of those is messing you up: the variable initializers aren't all run before the static initializer - initialization occurs in textual order.
So you're populating the collection... and then setting the reference to null.
Section 12.4.2 of the JLS guarantees it in step 9 of the initialization:
Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.
Demonstration code:
class Foo {
private static String before = "before";
static {
before = "in init";
after = "in init";
leftDefault = "in init";
}
private static String after = "after";
private static String leftDefault;
static void dump() {
System.out.println("before = " + before);
System.out.println("after = " + after);
System.out.println("leftDefault = " + leftDefault);
}
}
public class Test {
public static void main(String[] args) throws Exception {
Foo.dump();
}
}
Output:
before = in init
after = after
leftDefault = in init
So the solution is either to get rid of the explicit assignment to null, or to move the declarations (and therefore initializers) to before the static initializer, or (my preference) both.
The static initializer will get called when the class is loaded, which is normally when it is first 'mentioned'. So calling a static method would indeed trigger the initializer if this is the first time that the class gets referenced.
Are you sure the null pointer exception is from the allcountries.get(), and not from a null Country returned by get()? In other words, are you certain which object is null?
Theoretically, static block should get executed by the time classloader loads the class.
Country country = Country.findByISO("RO");
^
In your code, it is initialized the first time you mention the class Country (probably the line above).
I ran this:
public class Country {
private static Map<String, Country> allCountries;
static {
allCountries = new HashMap<String, Country>();
allCountries.put("RO", new Country());
}
public static Country findByISO(String cc) {
return allCountries.get(cc);
}
}
with this:
public class Start
{
public static void main(String[] args){
Country country = Country.findByISO("RO");
System.out.println(country);
}
}
and everything worked correctly. Can you post the stack trace of the error?
I would say that the problem lies in the fact that the static block is declared before the actual field.
Do you have allCountries = new HashMap(); in your static initializer block? The static initializer block is actually called upon class initialization.
public class CallingStaticMethod {
public static void method() {
System.out.println("I am in method");
}
public static void main(String[] args) {
CallingStaticMethod csm = null;
csm.method();
}
}
Can someone explain how the static method is invoked in the above code?
It's been optimized away by the compiler, simply because having an instance of the class is not necessary. The compiler basically replaces
csm.method();
by
CallingStaticMethod.method();
It's in general also a good practice to do so yourself. Even the average IDE would warn you about accessing static methods through an instance, at least Eclipse does here.
Java allows you to use a Class instance to call static methods, but you should not confuse this allowance as if the method would be called on the instance used to call it.
instance.method();
is the same as
Class.method();
The java language specification says the reference get's evaluated, then discarded, and then the static method gets invoked.
15.12.4.1. Compute Target Reference (If Necessary)
This is the same behavior when you use the this reference to call a static method. this gets evaluated then discarded then the method is called.
There is even an example in the specification similar to your example.
When a target reference is computed and then discarded because the invocation mode is static, the reference is not examined to see whether it is null:
class Test1 {
static void mountain() {
System.out.println("Monadnock");
}
static Test1 favorite(){
System.out.print("Mount ");
return null;
}
public static void main(String[] args) {
favorite().mountain();
}
}
Well this is perfectly ok. The static method is not being accessed by the object instance of class A. Either you call it by the class name or the reference, the compiler will call it through an instance of the class java.lang.Class.
FYI, each class(CallingStaticMethod in the above illustration) in java is an instance of the class 'java.lang.Class'. And whenever you define a class, the instance is created as java.lang.Class CallingStaticMethod = new java.lang.Class();
So the method is called on 'CallingStaticMethod ' and so null pointer exception will not occur.
Hope this helps.
Yes we can.
It will throw NullPointerException only if we are calling non static method with null object. If method is static it will run & if method is non static it will through an NPE...
To know more click here...