Final members with multiple constructor - java

I have a class like this.
public class AuditEvent {
private final String m_timeStamp;
private final String m_userName;
private int m_moduleId;
private int m_actionId;
private final String m_objectName;
private final String m_loggedInUserHostOrIP;
public AuditEvent() {
// No content
}
public AuditEvent(String timeStamp, String userName, String loggedInUserHostOrIP, String objectName) {
if (StringUtils.nullOrEmpty(timeStamp)) {
throw new IllegalArgumentException("The timeStamp field is not supplied");
}
if (StringUtils.nullOrEmpty(timeStamp)) {
throw new IllegalArgumentException("The userName field is not supplied");
}
if (null == objectName) {
throw new IllegalArgumentException("The objectName field is not supplied");
}
if (null == loggedInUserHostOrIP) {
throw new IllegalArgumentException("The loggedInUserHostOrIP field is not supplied");
}
m_timeStamp = timeStamp;
m_userName = userName;
m_loggedInUserHostOrIP = loggedInUserHostOrIP;
m_objectName = objectName;
}
But this gives an error that the final field m_userName may not have been initialized. It works if I don't have the empty constructor. Can anyone help me to solve this problem?

You have declared m_timeStamp as final but you have never initialized it in the empty constructor.
Every constructor should declare the variable if it's final, not just one. Or you can initialize it after declaring it, which will be valid aswell. eg
private final String m_timeStamp = "test";

Fill in all final fields in every constructor. Calling another constructor as follows helps:
public AuditEvent() {
this("" /*timeStamp*/, "" /*userName*/, "" /*loggedInUserHostOrIP*/, "" /*objectName*/);
}

A final field has to be initialized as the object is fully build and that the constructor has returned.
While here final fields are never valued :
public AuditEvent() {
// No content
}
So if you invoke this constructor and not the other one you violate the final constraints. Whereas the compilation error.
If the no arg constructor makes sense in your use case you could still define field initializers such as :
private final String m_timeStamp = "...";
private final String m_userName = "...";
Or as alternative chain the the no arg constructor to the args constructor :
public AuditEvent() {
this("...", "...", ...);
}

In java final variables must be initialized only once, before or inside constructor.

Related

Updating a static final field from an instance initializer

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;
}
}

How to make the value of a String variable not change after once assigned? [duplicate]

This question already has answers here:
Declare final variable, but set later
(7 answers)
Closed 5 years ago.
How can I make sure that the value of String variable doesnot change after being assigned once? Assignment is not at the time of declaration.
More clarity :-
String x = y; (y is another string)
Even if y changes x should not change. How to make sure this?
What I have tried :-
Created a custom class:-
public class MyDs {
private final String unitName;
public MyDs(String iUnitName){
unitName = iUnitName;
}
public String getUnitName(){
return unitName;
}
}
in the main method :-
String iName = "xyz";
MyDs MyDsObj = new MyDs(iName);
But even after this, the value changes when the variable changes.
How can I solve this issue?
Your class be should be design as mentioned in below code
public class TestingClas {
private String name;
public void setName(String name) {
if (this.name == null && name != null)
this.name = name;
}
public String getName() {
return name;
}
}
Now use below code for testing purpose
TestingClas testingClas = new TestingClas();
testingClas.setName("Abdul Waheed");
testingClas.setName("You cannot change me any more now");
String updatedString = testingClas.getName();
updatedString variable will be having old value
as far as I understand ,you should design your class in a way that your variable should be final . with this approach you set it in constructor and then nothing can make it changes. even the referance it is holding is changed the value remains the same I mean a new object is created in heap and value of your final variable is kept same. below is a kind of design which makes the variable x set once and never be able to changed afterwards. Of course this is in instance scope, for class scope you can make your class singelton etc.
public class Test {
private final String x;
private String y;
public Test(String x){
this.x=x;
}
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
public String getX() {
return x;
}
}
Change your MyDs class to a singleton class
Making this a singleton class ensures that the final String unitName is updated only once and then it will cannot be altered again.
public class MyDs {
private final String unitName;
private static MyDs myDs;
public static MyDs getMyDsObject(String iUnitName) {
if (myDs == null) {
myDs = new MyDs(iUnitName);
}
return myDs;
}
private MyDs(String iUnitName) {
unitName = iUnitName;
}
public String getUnitName() {
return unitName;
}
}
Here the values "xyz" is stored in unitName and doesnot get updated again when you change to "zxy".
MyDs MyDsObj = MyDs.getMyDsObject("xyz");
Log.i("value", "" + MyDsObj.getUnitName());
MyDs MyDsObj1 = MyDs.getMyDsObject("zxy");
Log.i("value",""+MyDsObj.getUnitName());
Well, you question is not really clear (and the comment section is really chaty...), but if you want to only be able to set a value once but not during the initialisation, setters are not a bad choice. Just add a constraint.
public class MyClass{
private static final String DEFAULT_VALUE = new String("");
private String value = DEFAULT_VALUE;
public final void setValue(String value){
if(this.value != DEFAULT_VALUE) //use the reference on purpose
throw new IllegalArgumentException("This value can't be changed anymore");
this.value = value;
}
// Don't return `DEFAULT_VALUE` to prevent someone to gain access to that instance
public final String getValue(){
return this.value == DEFAULT_VALUE ? null : this.value;
}
}
This will be done at runtime, but this would do the trick.
Now, this is an immutable instance, with some mutable instance you might want to do a copy of it to be sure it can't be modifier using the original reference.

some problems on declaring and calling of fields in java

I'm trying to access some fields from some class, but i face trouble when i want to call them.
This is the class which i have declared the fields :
public class InfoOfFriends {
public static final String Friends_List = "friends_list";
public static final String userName = "username";
public static final String STATUS = "status";
public static final String PORT = "port";
public static final String Ip = "Ip";
public static final String UserKey = "userKey";
public static final String Message = "message";
}
And this is where i want to use them :
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException
{
if (localName == "friend")
{
InfoOfFriends friend = new InfoOfFriends();
friend.username = attributes.getValue(InfoOfFriends.userName);
String status = attributes.getValue(InfoOfFriends.STATUS);
friend.port = attributes.getValue(InfoOfFriends.PORT);
if (status != null && status.equals("online")) {
friend.status = InfoStatus.ONLINE;
mOnlineFriends.add(friend);
} else if (status.equals("unApproved")) {
friend.status = InfoStatus.UNAPPROVED;
mUnApprovedFriends.add(friend);
} else {
friend.status = InfoStatus.OFFLINE;
mOnlineFriends.add(friend);
}
}
else if (localName == "user")
{
this.userKey = attributes.getValue(InfoOfFriends.UserKey);
}
super.startElement(uri ,localName, name, (org.xml.sax.Attributes) attributes);
}
These parts have errors :
friend.username = attributes.getValue(InfoOfFriends.userName);
friend.port = attributes.getValue(InfoOfFriends.PORT);
friend.status = InfoStatus.ONLINE;
friend.status = InfoStatus.UNAPPROVED;
friend.status = InfoStatus.OFFLINE;
Thanks for your time friends...
first of all are you sure that attributes has the correct values?
and remember to use as string comparator the equals() method
if (localName.equals("friend"))
instead of
if (localName == "friend")
You can't assign new values to final fields. Remove the final keyword to resolve the error.
Also you made all of the fields static and use them as keys to retrieve stuff from Attributes, but at the same time you want to assign new values to them - probably a bad idea. Try doing a separate class with final static keys to use for the Attributes retrieving, and a separate Friend class to assign the retrieved values to.

How to handle this situation for a Singleton class in Java?

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,

object array assignment problem

I have a problem where each element of my array seem to be reassigned.
class Car {
private static int nom = 0;
private static String whee = "";
public void setCar(int r, String s) {
this.nom = r;
this.whee = s;
}
}
class Rawr {
private Car[] jar = new Car[3];
public Mar() {
jar[0] = new Car();
jar[1] = new Car();
jar[2] = new Car();
jar[0].setCar(2, "yar");
jar[1].setCar(3, "tar");
jar[2].setCar(4, "sars");
}
}
If I printed it like jar[0].nom + jar[0].whee + jar[1].nom + jar[2].whee + jar[3].whee, the output would be
4 sars 4 sars sars
It's because your variables are static i.e. they belong to the class, rather than to an instance. Take a look at Java Tutorials | Understanding Instance and Class Members for more information about what this means.
You should remove the static keyword, so that they become instance variables.
Change
private static int nom = 0;
private static String whee = "";
to
private int nom = 0;
private String whee = "";
static means the variable is shared by all instances. (The fact you can use this to refer to static variables is a Java oddity.)
Your nom and whee fields are static. This means that they are tied to the class, and not to the object (instance) of the class.
Thus, when you assign a new value to this.nom, in reality, you assign a the value to Car.nom. The compiler allows referring to static variables through an object, but it's very bad practice. You should always refer to static fields by their class : Car.nom, Car.whee. This makes it clear that the nom and whee are static, and thus shared by all instances of the class. In this case, these fields should not be static : each Car instance has its own name and whee (whatever it might be).
A better way to structure your code is as follows.
class Car {
private final int nom;
private final String whee;
public Car(int nom, String whee) {
this.nom = nom;
this.whee = whee;
}
public String toString() { return num + " " + whee; }
}
class Rawr {
private final Car[] jar = {new Car(2, "yar"), new Car(3, "tar"), new Car(4, "sars")};
public String toString() {
return Arrays.toString(jar);
}
}

Categories

Resources