Java prohibits access of a final static field from an initializer. For example:
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
Example.exampleByPropertyA.put(propertyA, this); // <- Not permitted
}
}
However, if the update to the static Map is performed in a separate method that is called by the initializer, this is fine. For example:
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
addExample(this);
}
private addExample(Example example) {
Example.exampleByPropertyA.put(example.propertyA, example); // <- Permitted
}
}
Given this context, my question is: Does a call to a member method constitute a "freeze action" or is it indicative to the JVM that the object is, for all intents and purposes, "initialized"? Curious why this makes a difference.
I've done some searching, but haven't found anything that articulates this well.
Thank you in advance!
Does a call to a member method constitute a "freeze action" or is it indicative to the JVM that the object is, for all intents and purposes, "initialized"? Curious why this makes a difference.
The problem is that your class is initialised top to bottom. This means your static fields have not been initialised yet i.e. your Map is null.
Another approach is to add a static initialisation block to be called after everything has been initialised.
static {
for (Example e: values()) {
addExample(e);
}
}
private static addExample(Example example) {
Example prev = exampleByPropertyA.put(example.propertyA, example);
assert prev == null;
}
NOTE: You can see a final variable before it is initialised. This means final can have a before and after value even without using reflection.
public class A {
final String text = getText();
private String getText() {
System.out.println("text= " + text);
return "is set";
}
public static void main(String... args) {
new A().getText();
}
}
prints
text= null
text= is set
Using reflection you can alter final fields even after initialisation though you should avoid doing this unless there is no other option.
The correct way to do what you're trying to do, is to write a static initializer, which runs after all the enums have been created.
Defensive programming: You should also add a simple check to guard against programming errors.
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
static {
for (Example ex : values())
if (exampleByPropertyA.put(ex.propertyA, ex) != null)
throw new IllegalStateException("Duplicate propertyA: " + ex.propertyA);
}
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
}
}
Related
In the program I am making, I am trying to get a formatted season name for a given season(formatted so it . I keep the formatted names in an interface, since if I were to use a map, it would be unnecessarily regenerated, since I don't make an instance of TeamBuilder
The Seasons interface:
public interface Seasons {
/*
* Contains a formatted list of seasons.
*
* An interface is being used as an alternative to using a Map in the
* TeamBuilder class, since calling parseTeam would have to build
* mappings for the seasons each time it
* was called. This way, the formatted name can simply be grabbed
*/
final String Skyrise = "Skyrise";
final String Toss_Up = "Toss%20Up";
final String Sack_Attack = "Sack%20Attack";
final String GateWay = "Gateway";
final String Round_Up = "Round%20Up";
final String Clean_Sweep = "Clean%20Sweep";
final String Elevation = "Elevation";
final String Bridge_Battle = "Bridge%20Battle";
final String Nothing_But_Net = "Nothing%20But%20Net";
final String Starstruck = "Starstruck";
final String In_The_Zone = "In%20The%20Zone";
final String Turning_Point = "Turning%20Point";
}
The problem comes when I try to grab these seasons. My TeamBuilder class takes in an argument(String season), which is unformatted. My question is, is there any way that I can use a String argument for a method to get a specific item from an interface? This is the most preferable to using a HashMap, which would needlessly regenerate the same information
All these classes can be found on the Github page for this project.
If you want to do it in a typed way, you can use Enum for this:
enum Season{
Skyrise,Toss_Up, Sack_Attack;
#Override
public String toString() {
switch(this){
case Skyrise: return "Skyrise";
case Toss_Up: return "Toss%20Up";
case Sack_Attack: return "Sack_Attack";
default: return "";
}
}
}
public class main{
public static void printSeason(Seasons seasons){
System.out.println(seasons);
}
public static void main(String[] args) {
Seasons e = Seasons.Skyrise;
printSeason(e);
System.out.println(e);
}
}
Since the compiler internally invokes the toString(), you can pass the argument as a Seasons or a String like my example.
And if you still want to use a map without "unnecessarily regenerated" you can use a static field with static initializer like this:
class Seasons {
private static Map<String,String> map = new HashMap<>();
static {
map.put("Skyrise", "Skyrise");
map.put("Toss_Up", "Toss%20Up");
}
public static String getFormatted(String key){
return map.getOrDefault(key,"");
}
}
class main{
public static void main(String[] args) {
System.out.println(Seasons.getFormatted("Skyrise"));
}
}
Just to integrate on Snoob answer you can have enum with fields, so:
enum Season
{
Skyrise("Skyrise"),
Toss_Up("Toss%20Up"),
Sack_Attack("Sack%20Attack")
;
public final String fancyName;
private Season(String fancyName)
{
this.fancyName = fancyName;
}
}
You really have all the benefits without any drawback.
I need to write a unit test to test getRequired() method here by passing test data to private constructor private Example(String a, String b). Please help me with this.
public class Example {
private String str1 = null;
private String str2 = null;
public static void main(String[] args) {
Example e = new Example(args[0], args[1]);
String req = e.getRequired();
System.out.println(req);
}
private Example(String a, String b)
{
str1 = new String(a);
str2 = new String(b);
}
private String getRequired()
{
//code using str1 and str2 here
return "success";
}
}
From a black box testing standpoint
This code can't be tested. You can't even instantiate it, so there's no realistic way to go about this. There's no sense in testing something that can't be used like this.
If you want to make it testable, then you have to expose a static method to create instances of it. If that's a singleton or a factory, that's up to you - it's not apparent just from what you're showing us, but at least this would allow you to test the construction of it without really worrying about the private constructor.
You'd also have to make accessors to get at the fields, but make them package-private.
Further, invocations such as new String(String) in this case aren't needed, and may only serve to confuse you. You're passing in a String, so you don't need to create a new one.
Lastly, from a testing standpoint, getRequired() is tough to test; unless it mutates the state of the instance (which, again, you need to use to verify anything), there's no point to test it. It'll only ever return "success".
public class Example {
private String str1 = null;
private String str2 = null;
public static void main(String[] args) {
Example e = new Example(args[0], args[1]);
String req = e.getRequired();
System.out.println(req);
}
private Example(String a, String b) {
str1 = new String(a);
str2 = new String(b);
}
String getStr1() {
return str1;
}
String getStr2() {
return str2;
}
private String getRequired() {
//code using str1 and str2 here
return "success";
}
public static Example getNewInstance(String a, String b) {
return new Example(a, b);
}
}
From a white box testing standpoint
You can only use reflection to get at the private constructor and the fields to verify that they are set.
#Test
public void testExample() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Constructor<Example> exampleConstructor = Example.class.getDeclaredConstructor(String.class, String.class);
exampleConstructor.setAccessible(true);
Example example = exampleConstructor.newInstance("foo", "bar");
// verify
Field str1 = example.getClass().getDeclaredField("str1");
Field str2 = example.getClass().getDeclaredField("str2");
str1.setAccessible(true);
str2.setAccessible(true);
assertThat("foo", equalTo(str1.get(example)));
assertThat("bar", equalTo(str2.get(example)));
}
It looks like there are two other options.
Typically a private constructor implies that the class can not be sub-classed, and that by design the user of the exported API is not able to call the constructor directly. In this case there could be a public static factory method that would be implemented. This allows for instance control, which is not implemented below.
public static Example newInstance(String a, String b){
return new Example(a, b);
}
The other option, if you must test the constructor directly, is to promote the access modifier to the default, "package private", modifier.
Example(String a, String b){...}
You could add your unit test in the same package and test that way. Upgrading an access modifier from private to default in order to facilitate testing should not be a concern.
Error:
...
Caused by: java.lang.ExceptionInInitializerError
...
Caused by: java.lang.ClassCastException:
class com.evopulse.ds2150.TechTrees$BuildingTechTree
not an enum
at java.util.EnumSet.noneOf(Unknown Source)
at java.util.EnumSet.of(Unknown Source)
at com.evopulse.ds2150.TechTrees$BuildingTechTree.<clinit>(TechTrees.java:38)
Here is a snippet of my enumeration
public enum BuildingTechTree {
//Name SoftName Requirements
NONE ("NULL", null),
--> This next line is where it crashes
BARRACKS ("Barracks", EnumSet.of(NONE),
WALLS_SANDBAGS ("Sandbag wall", EnumSet.of(NONE),
POWERPLANT ("Power plant", EnumSet.of(BARRACKS)),
GUARDTOWER ("Guard Tower", EnumSet.of(BARRACKS));
Replacing EnumSet.of(NONE) and EnumSet.of(BARRACKS) with null, lets initialization work, but breaks my code, due to missing data structure... obviously, but I did it to test the rest of my code wasn't somehow the cause.
Removing EnumSet.of(NONE) and replacing with just NONE, and the same for BARRACKS, and changing all related variables, constructor, and methods, that didn't work either... (and even couldn't use the contains.all, since is wasn't "applicable to my changed variable"... )
I extended this example, using the second implementation:
https://gamedev.stackexchange.com/a/25652/48573
I also tried retracing my steps by copying the example verbatim. added
private static Set<BuildingTechTree> techsKnown;
techsKnown = (BuildingTechTree.BIODOME);
test = TechTrees.researchTech(techsKnown);
to another class to be called from for testing initialization. and had to change
public boolean researchTech(BuildingTechTree tech) {
to static
This resulted in the same "in not an enum" error. I don't have any rep, to comment on his answer to point out the initialization error...
Added info for both current answers, as both solutions cause the same new error:
public class TechTrees {
private static Set<BuildingTechTree> techsKnown;
public TechTrees() {
techsKnown = EnumSet.of(BuildingTechTree.NONE); //Using this
techsKnown = EnumSet.noneOf(BuildingTechTree.class); //Or this
}
public static boolean researchTech(BuildingTechTree tech) {
if (techsKnown.containsAll(tech.requirements)) { //Causes null pointer
return true; //exception # techsKnown
}
return false;
}
Your declaration structure is so clever it's a shame it doesn't work. But EnumSet apparently needs the enum to be fully initialized first. It tries to fetch the array of constants from the enum so that, among other things, it knows how much space is needed for its internal bitset.
Here's one workaround. It uses a helper method that creates an ordinary set (HashSet) first, and then, in a static initialization block, it iterates the enum constants and replaces all the sets with EnumSets.
public enum BuildingTechTree {
// Named constants
//Name SoftName Requirements
NONE ("NULL", null),
BARRACKS ("Barracks", setOf(NONE)),
WALLS_SANDBAGS ("Sandbag wall", setOf(NONE)),
POWERPLANT ("Power plant", setOf(BARRACKS)),
GUARDTOWER ("Guard Tower", setOf(BARRACKS));
private final String softName;
private Set<BuildingTechTree> requirements;
private BuildingTechTree(String softName, Set<BuildingTechTree> requirements) {
this.softName = softName;
this.requirements = requirements;
}
private static Set<BuildingTechTree> setOf(BuildingTechTree... values) {
return new HashSet<>(Arrays.asList(values));
}
static {
for (BuildingTechTree v : values()) {
if (v.requirements == null) {
v.requirements = EnumSet.noneOf(BuildingTechTree.class);
} else {
v.requirements = EnumSet.copyOf(v.requirements);
}
}
}
}
You have a chicken and egg problem. You could refactor your enum to something like this:
public enum BuildingTechTree {
NONE("NULL"),
BARRACKS("Barracks"),
WALLS_SANDBAGS("Sandbag wall"),
POWERPLANT("Power plant"),
GUARDTOWER("Guard Tower");
static {
NONE.trees = EnumSet.noneOf(BuildingTechTree.class);
BARRACKS.trees = EnumSet.of(NONE);
WALLS_SANDBAGS.trees = EnumSet.of(NONE);
POWERPLANT.trees = EnumSet.of(BARRACKS);
GUARDTOWER.trees = EnumSet.of(BARRACKS);
}
private String name;
private Set<BuildingTechTree> trees;
private BuildingTechTree(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Set<BuildingTechTree> getTrees() {
return Collections.unmodifiableSet(trees);
}
}
EDIT:
regarding your second problem: you're accessing a static variable, from a static method. But this variable is initialized when the constructor of the class has been called (which is a huge design problem). Don't use non-final static fields. And don't initialize static fields from instance methods or constructors. That doesn't make sense. You don't set the color that all cars should have when constructing a car. Initialize your static fields statically:
public class TechTrees {
private static final Set<BuildingTechTree> TECHS_KNOWN =
EnumSet.of(BuildingTechTree.NONE);
public static boolean researchTech(BuildingTechTree tech) {
return TECHS_KNOWN.containsAll(tech.requirements));
}
}
I have some doubts regarding how to do the following operation on a class that follow the Singleton model.
I have this original Singleton class:
public class ThreadsManager {
// I can have only one instance:
private final static ThreadsManager instance = new ThreadsManager();
// Private constructor:
private ThreadsManager() {
}
public static ThreadsManager getInstance(){
return instance;
}
}
Ok, this work well but now I have to modify it adding a new property (a String named userName) that have to be initialized when the singleton object is build and that
can not be changed at a later time
So I am trying to do something like it:
public class ThreadsManager {
private final static ThreadsManager instance = new ThreadsManager();
private final static String userName;
private ThreadsManager() {
}
public static ThreadsManager getInstance(String user){
userName = user;
return instance;
}
}
So I am trying to add the new String userName variable that is static (once for the class) and final (can not be changed at a second time)
My problem is that Eclips marks as an error the lines:
1) private final static String userName; saying to me that:
The blank final field userName may not have been initialized
It seems that would that the field will be initialized (I can initialize it to null but since it is final...I can't initialize later in the constructor)
2) userName = user; say to me that:
The final field ThreadsManager.userName cannot be assigned
So what is the best solution to handle this situation?
If I remove the final from the userName variable definition it seems to me that work well but then I can change this value but maybe I simply can not provide the setter method for this field so I prevent external changes....
Some ideas?
I think you want a singelton 'with arguments'. This should explain it :
Singleton with Arguments in Java
It is not going to be singleton if you want multiple state of an instance of that class,
you could create a cache of Object keyed with user so it would still be singleton for same state asked
private final Map<String, ThreadsManager> instanceCache = Collections.synchronizedMap<String, ThreadsManager>();
Also make sure you don't leak memory if you have tons of states for this class
Since this class is a Singleton then the name shouldn't really change too much. I would suggest just keeping it as a constant inside the class. If the name might change when the program is executed on different occasions then see Solution 2 below.
Solution 1:
public class ThreadsManager
{
private final static ThreadsManager instance = new ThreadsManager();
private String userName;
private ThreadsManager()
{
final String name = "Name";
userName = name;
}
public static synchronized ThreadsManager getInstance(String user)
{
return instance;
}
}
Solution 2:
If you really want to set the name of the Singleton and every time the program is execute the name might be different. Just add this method:
private String userName = null;
// Can only be set after Singleton is created and when userName is null.
public void setName(String n)
{
if(userName == null)
userName = n;
}
Don't make your getInstance() method have a parameter, that is a bad design. Every time someone, or you, tries to get an instance from your class they/you have to provide a parameter which will be 99% of the time be irrelevant.
You can do it using a nested class.
public class ThreadsManager {
private static String userName;
private ThreadsManager() {
}
public static ThreadsManager getInstance(String user){
if (userName == null)
userName = user;
// the holder's instance is only initialised at this point,
// after userName is set.
return Holder.instance;
}
static class Holder {
private final static ThreadsManager instance = new ThreadsManager();
}
}
First of all:
private final static String userName
may only be initialized inside the private constructor or during definition.
Secondly
You may end up with a null instance, so you might do something like this:
public class ThreadsManager {
private final static ThreadsManager instance = new ThreadsManager();
private String userName;
private ThreadsManager() {
}
private ThreadsManager(String user) {
userName = user;
}
public static ThreadsManager getInstance(String user){
if(instance == null) {
instance = new ThreadsManager(user);
} else {
Logger.getInstance().logWarning("User has already been set. Will continue with user ["+username+"].);
}
return instance;
}
}
The handling of how to deal with a second user name handed needs some thinking.
Overall you should try to keep the getInstance() method parameter free since it leads to the above mentioned problems.
How about
public class ThreadsManager {
private final static ThreadsManager instance = new ThreadsManager();
private static String userName;
public static synchronized ThreadsManager getInstance( String user ) {
if ( username == null ) { userName = user; }
return instance;
}
That would ensure userName is only set the first time.
It is, however, potentially very confusing semantics for a singleton to take a parameter that is ignored on subsequent getInstance()'s - possibly even race-condition-prone, depending on your use-case.
Cheers,
I am experimenting here a bit.
Say I have a class :
static class MyClass {
static String property = "myProperty";
}
and a method:
public static void myMethod0(Class<MyClass> clazz) {
try {
MyClass myClass = clazz.newInstance();
System.out.println (myClass.property);
} catch (Exception e) {
e.printStackTrace();
}
}
and to test it:
public static void main(String[] args ) {
myMethod0(MyClass.class);
}
myMethod0 would work here, however, I am creating a new instance in order to reach the property.
Since the properties are static I should be able to reach them without actually creating any instance. For example as you would do when reaching a static property, ie MyClass.property
To summarize:
Is it possible to reach the static property of MyClass, by having Class clazz = MyClass.class ?
Thanks !
**
EDIT:
**
To put the above in perspective and what I am actually trying to accomplish:
public static class PDF_1 { public static PDF_1 it = new PDF_1();
static String contentType = "application/pdf";
static String fileEnding = "pdf";
}
static void myMethod0(PDF_1 pdf) {
System.out.println(pdf.fileEnding);
}
public enum PDF_2 {it;
static String contentType = "application/pdf";
static String fileEnding = "pdf";
}
static void myMethod1(PDF_2 pdf) {
System.out.println(pdf.fileEnding);
}
public static void main(String[] args ) {
myMethod0(PDF_1.it); // Works fine! However very verbose because of public static PDF_1 it = new PDF_1();
myMethod1(PDF_2.it); // Works fine! Somewhat verbose though because of the "it" keyword
}
The whole idea as to what I am trying to accomplish with this, is that too often do I see people declare lots of strings, ie:
static class Constants {
static String PDF_CONTENT_TYPE = "application/pdf";
static String PDF_FILE_ENDING = "pdf";
static String HTML_CONTENT_TYPE = "text/html";
static String HTML_FILE_ENDING = "html";
}
// There is no way knowing what type the method actually wants. Is it contentType, fileEnding or something entirely different ?
public void myMethod(String str) {
}
What I am trying to achieve is something that would allow you to pass a main class/enum, ie: PDF and the method will itself determine what it will use. The caller will just know what to pass, a PDF or HTML class/enum. I am also looking for something that is this refactor friendly as well. It is also of interest not to complicate the declaration of this creation. I find fully blown enums just as obtrusive as a class, and can be hard to read. The ide a is that I am just grouping the two strings in a parent object "PDF" and "HTML". An enum:
public enum SomeType {
PDF("application/pdf", "pdf"), HTML(...);
String contentType;
String fileEnding;
// Constructor ...
}
Would not allow you to declare a method and specify that this method expects the HTML stuff. Only that the enum type is of type SomeType. There is a risk that "someone" would pass SomeType.PDF to that method. What I am doing with the enum and class seems like a noob solution, and the Java language should provide a feature like this, or does it already?
Does this make sense?
You could use reflection
System.out.println(myClass.getDeclaredField("property").get(null));
The get-method usually requires an instance to get the attribute from, but since property is static, you may pass it a null.
I hope you meant this - I wrote tests with hamcrest - so don't wonder ;)
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import org.junit.Test;
public class TestEnumEnding {
#Test
public void whenMethod1WithFiletypeHtmlWeShouldGetStringText_Html() throws Exception {
// Arrange
String contentType = null;
// Act
contentType = method1(Filetype.HTML);
// Assert
assertThat(contentType, is("text/html"));
}
#Test
public void whenMethod1WithFiletypePdfWeShouldGetapplication_pdf() throws Exception {
// Arrange
String contentType = null;
// Act
contentType = method1(Filetype.PDF);
// Assert
assertThat(contentType, is("application/pdf"));
}
private static String method1 (Filetype anyFiletype) {
return anyFiletype.getContentType();
}
public enum Filetype {
HTML("html","text/html"), PDF("pdf","application/pdf");
private final String fileEnding;
private final String contentType;
private Filetype(String fileEnding, String contentType) {
this.fileEnding = fileEnding;
this.contentType = contentType;
}
public String getFileEnding() {
return this.fileEnding;
}
public String getContentType() {
return this.contentType;
}
}
}
public enum PDF { it;
static String contentType = "application/pdf";
static String fileEnding = "pdf";
}
static void myMethod1(PDF pdf) {
System.out.println(pdf.fileEnding);
}
public static void main(String[] args ) {
myMethod1(PDF.it); // Works fine! Somewhat verbose though because of the "it" keyword. Not 100% ideal!
}