Issues with constants in static block java - java

I have two questions regarding the static block and Constants with below code.
Constant (or even simple Static variable) cannot be directly referrenced from static block. It gives error saying "Cannot reference a field before it is defined". But it is ok when accessing through a static method.
If I assign a value to a constant in static block's catch as mentioned below it gives error saying "The final field NAME may already have been assigned". But if asigning in catch it gives error saying "The blank final field NAME may not have been initialized".
I want to know why is it bahaving like this?
Code :
public class TestStaticblock {
static{
try {
// NAME = dummyStringValue() + NAME_APPENDER; // Cannot reference a field before it is defined
// NAME = dummyStringValue() + getNameAppender(); // This is OK
NAME = dummyStringValue();
} catch (Exception e) {
NAME = null; // The final field NAME may already have been assigned
}
}
private static String dummyStringValue() throws Exception{
return "dummy";
}
private static String getNameAppender() throws Exception{
return NAME_APPENDER;
}
private static final String NAME; // If I comment Catch it says "The blank final field NAME may not have been initialized"
private static String NAME_APPENDER = "appender";
}

You can only assign to NAME once (because it is final). Assign the result to a temporary variable, and then assign to NAME (and don't silently swallow Exceptions). Something like,
static {
String temp = null;
try {
temp = dummyStringValue();
} catch (Exception e) {
e.printStackTrace();
}
NAME = temp;
}
The reason you can't assign NAME the way your are currently is because the compiler performs static program analysis (specifically, the data-flow analysis) and that detects that there is a possible code path where NAME is not assigned. And because NAME is final, that is a compilation error.

You cannot use a static final field in a static block before it has been assigned, yet you can access it just by calling a method.
For example, this code prints null FOO:
public class Main {
static final String FOO;
static {
foo();
FOO = "FOOFOO".substring(0, 3);
foo();
}
static void foo() {
System.out.println(FOO);
}
public static void main(String[] args) {}
}
This is undeniably odd, but I guess it would have made the language considerably more complicated to make things such as this impossible.
As for your second question, this doesn't compile.
static{
try {
NAME = dummyStringValue();
} catch (Exception e) {
NAME = null; // The final field NAME may already have been assigned
}
}
This is also odd. If an exception is thrown it can only have occurred inside the method dummyStringValue(). Since you can't assign values to final fields inside a method, it is completely impossible for the NAME variable to have already been assigned in the catch block. Therefore there is no possible code path where NAME is not assigned. You'd think it ought to work in the same way as
static{
if (someCondition()) {
NAME = dummyStringValue();
} else {
NAME = null;
}
}
which compiles fine.
I guess the reason is again that it would have made the language much more complicated to allow this. There is no great benefit to allowing it as you can just use a method or a temp variable as indicated in the other answers. Exceptions just are more complicated than if statements - they can act almost like a goto. A good point was made by #ElliottFrisch in the comments. What about something like this:
static{
try {
NAME1 = dummyStringValue1();
NAME2 = dummyStringValue2();
} catch (Exception e) {
// Has NAME1 been assigned here?
}
}

Perhaps this would be of assistance to those looking for something similar.
There is a little-known feature of Java (discussed in JavaSpecialists Throwing Exceptions from Fields that if you wish to initialise a final instance variable (i.e. NOT a static) to the result of a method call that throws an exception then you can avoid the obvious error by adding a constructor that throws the exception.
Note that this solution only works for non-statics (not what you are observing).
public class TestStaticblock {
private final String NAME = dummyStringValue();
// Adding this removes the "unreported Exception" above.
public TestStaticblock() throws Exception {
}
private static String dummyStringValue() throws Exception {
return "dummy";
}
}

My strong personal preference is to use methods instead of static initializer blocks which initializer a single variable:
private static final String NAME = getName();
private static String getName() {
try {
return something();
} catch (Exception e) {
return null;
}
}
You don't get issues like the one you have described.
You can only calculate one field value, so you are not tempted to throw lots of things into the same block.
You can re-invoke a method to test it.

Related

can not initialize static final variable in try/catch

I am trying to initialize a static final variable. However, this variable is initialized in a method which can throw exception, therefor, I need to have inside a try catch block.
Even if I know that variable will be either initialized on try or on catch block, java compiler produces an error
The final field a may already have been assigned
This is my code:
public class TestClass {
private static final String a;
static {
try {
a = fn(); // ERROR
} catch (Exception e) {
a = null;
}
}
private static String fn() throws Exception {
throw new Exception("Forced exception to illustrate");
}
}
I tried another approach, declaring it as null directly, but it shows a similar error (In this case, it seems totally logic for me)
The final field TestClass.a cannot be assigned
public class TestClass {
private static final String a = null;
static {
try {
a = fn(); // ERROR
} catch (Exception e) {
}
}
private static String fn() throws Exception {
throw new Exception("Forced exception to illustrate");
}
}
Is there an elegant solution for this?
You can assign the value to a local variable first, and then assign it to the final variable after the try-catch block:
private static final String a;
static {
String value = null;
try {
value = fn();
} catch (Exception e) {
}
a = value;
}
This ensures a single assignment to the final variable.
Final variables can only be set once.
You cannot (and do not need to) set a to null in the catch block.
Make the following change:
public class TestClass {
private static final String a = setupField();
private static String setupField() {
String s = "";
try {
s = fn();
} catch (Exception e) {
// Log the exception, etc.
}
return s;
}
private static String fn() throws Exception {
return "Desired value here";
}
private static final String a = null;
properties that are final are only initialise once. Either in the Constructor or the way you did it here. You cannot give 'a' a new value after you have given it the value null. If you dont have a final you can set the value via the fn function
It's because final variable can only be assigned only once and it can't be reassigned again.
Nothing to do with try/catch

Try - Catch around Enum

I want to save a method in an Enum, but Class.getDeclaredMethod is throwing NoSuchMethodException, so how can I handle it?
My Code:
public enum Card {
OPENPRISON(false, Cards.class.getDeclaredMethod("", Player.class));
private boolean isInstant;
private Method method;
private Card(boolean isInstant, Method method){
this.method = method;
this.isInstant = isInstant;
}
public boolean isInstant() {
return isInstant;
}
public void run(Player p){
}
}
and OPENPRISON is the problem
An immediate technical issue is that you're not providing a method name in your call to getDeclaredMethod():
OPENPRISON(false, Cards.class.getDeclaredMethod("", Player.class));
A larger issue is why you need to use reflection at all.
An enum value is a constant. What can you do with reflection that you could not as easily do with a static method? Or with a method outside the enum?
Well your code throws a checked exception, so you could use a method:
OPENPRISON(false, foo());
private static Method foo() {
try {
return Cards.class.getDeclaredMethod("", Player.class);
} catch (NoSuchMethodException e) {
return null;
}
}
Of course, the question remains if you cannot solve your problem without reflection - most likely it is possible.

Why program is not allowing to initialize the static final variable?

I came across the Java code below which looks good at first but never compiles :
public class UnwelcomeGuest {
public static final long GUEST_USER_ID = -1;
private static final long USER_ID;
static {
try {
USER_ID = getUserIdFromEnvironment();
} catch (IdUnavailableException e) {
USER_ID = GUEST_USER_ID;
System.out.println("Logging in as guest");
}
}
private static long getUserIdFromEnvironment()
throws IdUnavailableException {
throw new IdUnavailableException(); // Simulate an error
}
public static void main(String[] args) {
System.out.println("User ID: " + USER_ID);
}
}//Class ends here
//User defined Exception
class IdUnavailableException extends Exception {
IdUnavailableException() { }
}//Class ends here
Below is the error message which comes in the IDE :
variable USER_ID might already have been assigned.
Is there any problem with the value assignment to the static final variable ?
Final variables allow at most one assignment in the constructor or the initializer block. The reason this does not compile is that Java code analyzer sees two assignments to USER_ID in branches that do not look mutually exclusive to it.
Working around this problem is simple:
static {
long theId;
try {
theId = getUserIdFromEnvironment();
} catch (IdUnavailableException e) {
theId = GUEST_USER_ID;
System.out.println("Logging in as guest");
}
USER_ID = theId;
}
The fact that you have used the assignment operator to throw the Exception in the following line:
USER_ID = getUserIdFromEnvironment();
means that the compiler thinks that there is a possibility of assignment, especially given the fact that it is declared as final.
Since the compiler gave you an that kind of error indicatesthat the variable has been creaated (and perhaps changed) somewhere else. It is good to change the name of your variable whereever it appears in your code.

NullPointerException when calling a getter

I have already done research on this question, and also tried to figure it out by myself but no luck. So I decided to ask it.
Basic info:
There are two classes. FBClient, and State. In FBClient, I have a static variable of it's type, fbc, a StateManager instance, which just has some methods to work with State stuff, some constants and two getters. In State, I am trying to initialize a BufferedImage.
public class FBClient
{
//Static
public static FBClient fbc;
//In init method
private StateManager stateManager;
//Constants
private final int INIT_FRAME_WIDTH = 320, INIT_FRAME_HEIGHT = (INIT_FRAME_WIDTH / 4) * 3, SCALE = 3, FRAME_WIDTH = INIT_FRAME_WIDTH * SCALE, FRAME_HEIGHT = INIT_FRAME_HEIGHT * SCALE;
public static void main(String[] args)
{
try
{
//First call in exception chain:
fbc = new FBClient();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
}
private FBClient()
throws IOException
{
//Second call in exception chain:
init();
}
private void init()
throws IOException
{
stateManager = new StateManager();
//Third call in exception chain:
stateManager.addState(new MainMenu((byte) 0, "Main Menu")); //MainMenu is the subclass of State, and the constructor just calls "super(0, "Main Menu")"
}
public int getFRAME_HEIGHT()
{
return FRAME_HEIGHT;
}
public int getFRAME_WIDTH()
{
return FRAME_WIDTH;
}
}
public abstract class State
{
protected final byte ID;
protected final String NAME;
protected final BufferedImage SCREEN;
protected final Graphics2D GRAPHICS;
public State(byte id, String name)
{
this.ID = id;
this.NAME = name;
//Exception cause:
this.SCREEN = new BufferedImage(FBClient.fbc.getFRAME_WIDTH(), FBClient.fbc.getFRAME_HEIGHT(), BufferedImage.TYPE_INT_RGB);
this.GRAPHICS = SCREEN.createGraphics();
}
}
More info:
If I put literals in BufferedImage initialization it works.
If I initialize two variables in the State class, assigning them literals and putting those variables in initialization, it works.
If instead of assigning literals to those variables I assign them FBClient.fbc.getFRAME_WIDTH() and FBClient.fbc.getFRAME_HEIGHT(), it throws a NullPointerException.
If I make a System.out.println(getFRAME_WIDTH + " : " + getFRAME_HEIGHT) in FBClient class, it prints out properly, but if I do it in State class (and off course adding FBClient.fbc. before it), it throws a NullPointerException.
If I make FRAME_WIDTH and FRAME_HEIGHT constants public, and I try to access them from State
class by doing FBClient.fbc.FRAME_WIDTH and FRAME_HEIGHT, it throws a NullPointerException.
If I try to access the constants from FBClient class directly, instead of getters, it still prints out properly.
Finally
Thank you for taking your time, and if you need more information to work with, ask me in the comments and I'll provide it. Also, I apologise if the question is not constructed well/not explained well. If that's the case, tell me how can I improve it. And also, I apologise if this question was asked and answered once already, I may have missed it, but as I said, I did my research.
Edit #1
A comment suggested I print out a fbc value, to see if it's null.
So I added this line of code to the State constructor:
if(FBClient.fbc != null) System.out.println("Not null"); else System.out.println("Null");
And, as suspected, it printed out null. Why is that? I clearly initialized the variable in the main method...
You are referring to FBClient.fbc before it is assigned (actually in the constructor since fbc get assigned after the constructor finished working). To fix it add static to the final values, make the getter static and acess it with FBClient.getFRAME_HEIGHT(). You don't need non-static final variables.
The reason you are having a problem is because you are trying to reference FBClient.fbc within its constructor call and the object hasn't finished its own construction. It's not immediately obvious you're doing this but if you follow the code within the constructor you are calling init() which ultimately calls to a State constructor, which in turn tries to use FBClient.fbc.getFRAME_WIDTH().
I suggest you don't call init() within the FBClient constructor and change your main method code to:
public static void main(String[] args)
{
try
{
//First call in exception chain:
fbc = new FBClient();
fbc.init();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
}
Hope this helps.
I think your FBClient.fbc is null.

unique enum name token determined during class initialization

I've defined the following enum in Groovy, though for the purpose of this question it could be Java code:
enum FestivalType {
BIG_MUSIC,
SMALL_MUSIC,
FILM,
FOOD_AND_DRINK;
private static Set<String> allSearchTokens = new HashSet<String>();
FestivalType() {
String searchToken = this.name().tokenize('_').first().toLowerCase();
if (searchToken in allSearchTokens) {
throw new RuntimeException("Duplicate search token");
} else {
this.searchToken = searchToken;
allSearchTokens.add(searchToken);
}
}
final String searchToken;
}
What I'm trying to do in the constructor is establish whether the first token in the name of each enum constant is unique, where _ is used as the token separator.
However, this code doesn't work because allSearchTokens is not initialized until after all the constants are instantiated, so I get a NullPointerException here
allSearchTokens.add(searchToken)
You can work around this as follows:
public enum FestivalType {
BIG_MUSIC,
SMALL_MUSIC,
FILM,
FOOD_AND_DRINK;
private static class SetHolder {
static Set<String> allSearchTokens = new HashSet<String>();
}
final String searchToken;
FestivalType() {
String searchToken = name().split("_")[0].toLowerCase();
if (SetHolder.allSearchTokens.contains(searchToken))
throw new RuntimeException("Duplicate search token");
this.searchToken = searchToken;
SetHolder.allSearchTokens.add(searchToken);
}
}
This compiles because of the java specification that all static initializers must be completed before the class is used. By making the Set a static field of a sttic inner class, you guarantee that it will be initialized before the first enum is constructed.
Also, I took the liberty of changing/fixing a few things in your code:
Use a Set rather than a List: Values are unique
Use split(): There is not such method tokenize() for String in java
Remove else: After a return or throws, else is always redundant because execution of the block is halted by these keywords (there is no "else" to handle)
As an aside, this technique is also great for lazy initialization of singletons:
public class MyLazySingleton() {
private static class InstanceHolder {
static MyLazySingleton INSTANCE = new MyLazySingleton();
}
public static MyLazySingleton getInstance() {
return InstanceHolder.INSTANCE;
}
}
The INSTANCE field is only constructed when the getInstance() method is first called!
Look mom! Lazy initialization without locks, without null checks, without synchronization of any kind and 100% bulletproof! (Object deserialization hacks notwithstanding)
It's magic :)
I have done something similar and the following has worked for me:
enum MyEnum{
Enum1, Enum2;
private static List<String> myList;
private static void addToList(MyEnum enum){
if(myList == null){
myList = new ArrayList<String>();
}
myList.add(enum.name());
}
private MyEnum(){
addToList(this);
}
}

Categories