Where it is better to initialize fields? In constructor (var.1) or on declaration (var.2)?
var. 1
public class UtilWebLoading {
private int data;
private Context context;
public UtilWebLoading(Context context) {
this.context = context;
data = 100;
}
...
}
var. 2
public class UtilWebLoading {
private int data = 100;
private Context context;
public UtilWebLoading(Context context) {
this.context = context;
}
...
}
In var. 1 the context has been initiated, while in var. 2 it will be null!
Use the first one.
I personally prefer to initialize fields when I have sufficient context to do so. For example, if I have a List field I usually initialize it upon declaration (unless the class requires the user to pass an implementation of their choosing), but if I have an array that requires a size to be passed, I'm forced to wait for a constructor call.
Hence, in your case, the second snippet does not have enough context to initialize Util at declaration, because no valid Context member exists.
Related
This question already has answers here:
Are fields initialized before constructor code is run in Java?
(5 answers)
Closed 12 months ago.
Hi I have the following code and as I am stepping through it in the debugger I notice that the constructor does not get invoked and hence mContext variable initiated within it remains null.
As I am stepping through the debugger the getInstance() function will call the constructor RaceTimeDataContract(Context context), however if I try to step into the constructor it does not and instead the debugger steps to the line where TABLE_NAME is being initialized. The problem is since mContext remains null, then exception is being thrown.
Anyone know what may be causing this behavior? Code is below:
public class RaceTimeDataContract implements BaseColumns{
private static RaceTimeDataContract sInstance;
private static Context mContext;
private RaceTimeDataContract(Context context) {
this.mContext = context; // This is not getting called
}
private RaceTimeDataContract(){}
public static RaceTimeDataContract getInstance(Context context) {
if (sInstance == null) {
sInstance = new RaceTimeDataContract(context.getApplicationContext());
}
return sInstance;
}
// mContext remains null and forces a exception
private final String TABLE_NAME = mContext.getResources().getString(R.string.table_name);
Appreciate any feedback!
When creating new instances, inline field initialisation is performed before the constructor is called. One simple fix in your case is to move the field initialisation into the constructor after the context is set
e.g. (I've reorganised the code a little, and dropped the this on mContext since it is a static member)
public class RaceTimeDataContract implements BaseColumns {
private static RaceTimeDataContract sInstance;
private static Context mContext;
public static RaceTimeDataContract getInstance(Context context) {
if (sInstance == null) {
sInstance = new RaceTimeDataContract(context.getApplicationContext());
}
return sInstance;
}
private final String TABLE_NAME;
private RaceTimeDataContract(Context context) {
mContext = context;
this.TABLE_NAME = mContext.getResources().getString(R.string.table_name);
}
// The below is invalid as it doesn't set TABLE_NAME and should probably be removed
// private RaceTimeDataContract(){}
}
The above isn't very idiomatic and would be better re-arranged to support a singleton better. There are many ways to do this but some general things which would be a benefit are
Storing the context on the instance object, and not statically
Preventing race conditions on getInstance
Removing the default constructor
Assuming you don't retrieve the instance often this can easily be accomplished by synchronising on the getInstance call. e.g.
public class RaceTimeDataContract implements BaseColumns {
private static RaceTimeDataContract sInstance;
public static synchronized RaceTimeDataContract getInstance(Context context) {
if (sInstance == null) {
sInstance = new RaceTimeDataContract(context.getApplicationContext());
}
return sInstance;
}
private final Context mContext;
private final String tableName;
private RaceTimeDataContract(Context context) {
this.mContext = context;
tableName = mContext.getResources().getString(R.string.table_name);
}
}
As a last note it is atypical of a singleton to take a parameter in the getInstance method but always return the same object - you can imagine in this case that if getInstance is called a second time with a different context then we get the original instance which may have an incorrect table name.
If you do need a singleton per context you can store each instance per context in something like a Map<Context, RaceTimeDataContract>, probably using a ConcurrentHashMap, and it would be better to think of it as some kind of reference cache or factory rather than a singletone.
If possible, it is better to just have a zero parameter getInstance method which can retrieve the singleton context statically the first time it is required. This can open your class up to more typical/simpler singleton patterns like enum singletons and static singleton holders.
I was making a food ordering application where I got stuck. I am calling the constructor of my class. Then, after assignment, this.listData my ArrayList is being reported redundant.
public class CartAdapter extends RecyclerView.Adapter<CartViewHolder> {
private List<Order> listData = new ArrayList<>();
private Context context;
public CartAdapter(List<Order> listData, Context context) {
this.listData = listData;
this.context = context;
}
}
Probably your IDE gives you the message that the following initialisation is redundant, not the field itself.
private List<Order> listData = new ArrayList<>();
The idea is that you have only one constructor, and this constructor expects all the time a List<Order>. This means that each time you make an instance of the class, you will be able to use the only constructor you provided, in which the field listData will have the value of the first parameter of the only constructor, so there is no need to initialize the field like that. This is why you get the "redundant initialisation" warning.
If you want to have a way of initialising the listData as an empty ArrayList, then you can provide an constructor where you don't handle the listData field. Otherwise, declaring private List<Order> listData; will do "the trick".
I have an abstract class which is supposed to have an (int) attribute that can't be modified after initialization and is pre-set to 1; what is the best way to do it?
Should I make it final?
The requirement is that inside the class I will have one and only one constructor(with parameters), and no setters.
If so, how do I make it 1 by default if it's final and (I suppose) I'm going to initialize it in the constructor?
Thanks!
As a matter of fact your can even hard code it, if it will always be a constant value.
For example if your variable should always be 25 you can do something like this:
public abstract class Test
{
protected final int pressure = 25;
//Constructor
public Test()
{
// TODO Auto-generated constructor stub
}
}
But if you evaluate the value on runtime you need to set it with in the constructor of the Object:
public abstract class Test
{
protected final int pressure;
//Constructor
public Test(int pressure)
{
this.pressure = pressure;
}
}
Note that in this case the variable must not be assigned earlier!
The question, if a final variable should be used depends on it's purpose. A final variable can only be assigned once over it's entire lifetime. If you have to modify it in any kind you should not use it.
You could use constructor overloading to achive this. See the example:
public abstract class TestClass{
private final int otherParam;
private final int fixedParam;
public TestClass(final int otherParam){
this.otherParam = otherParam;
this.fixedParam = 1;
}
public TestClass(final int otherParam, final int fixedParam){
this.otherParam = otherParam;
this.fixedParam = fixedParam;
}
}
You should use a constructor with parameters to set your initial values. Then, as you say, don't create any setter, and be sure your fields are private, so that no one can access it.
This way, you will do what you want, having fields initialized but never change after that.
This is my first time using SharedPreferences in my Android app. Since I will be using the SharedPreferences over and over again, I have created a utility class called SharedPreferencesUtil which contains a lot of static methods which allow me to access and modify the values. For example:
/**
* This method is used to add an event that the user
* is looking forward to. We use the objectId of a ParseObject
* because every object has a unique ID which helps to identify the
* event.
* #param objectId The id of the ParseObject that represents the event
*/
public static void addEventId(String objectId){
assert context != null;
prefs = context.getSharedPreferences(Fields.SHARED_PREFS_FILE, 0);
// Get a reference to the already existing set of objectIds (events)
Set<String> myEvents = prefs.getStringSet(Fields.MY_EVENTS, new HashSet<String>());
myEvents.add(objectId);
SharedPreferences.Editor editor = prefs.edit();
editor.putStringSet(Fields.MY_EVENTS, myEvents);
editor.commit();
}
I have a few of questions:
1. Is it a good decision to have a utility class SharedPreferencesUtil ?
2. Is the use of assert proper?
3. Is that how I will add a String to the set?
In general I think utility classes like this are fine. A few recommendations I'd have are:
Initialize your Context in a subclass of Application (in Application.onCreate()) and store a reference to that in your utility class. You don't have to worry about a memory leak if you ensure you only use the application context instead of an Activity context, and since SharedPreferences doesn't use any theme attributes, there's no need to use an Activity context anyway.
Check and throw an exception warning that the class hasn't been initialized yet if you try to use it without initialization. This way you don't need to worry about checking for a null context. I'll show an example below.
public final class Preferences {
private static Context sContext;
private Preferences() {
throw new AssertionError("Utility class; do not instantiate.");
}
/**
* Used to initialize a context for this utility class. Recommended
* use is to initialize this in a subclass of Application in onCreate()
*
* #param context a context for resolving SharedPreferences; this
* will be weakened to use the Application context
*/
public static void initialize(Context context) {
sContext = context.getApplicationContext();
}
private static void ensureContext() {
if (sContext == null) {
throw new IllegalStateException("Must call initialize(Context) before using methods in this class.");
}
}
private static SharedPreferences getPreferences() {
ensureContext();
return sContext.getSharedPreferences(SHARED_PREFS_FILE, 0);
}
private static SharedPreferences.Editor getEditor() {
return getPreferences().edit();
}
public static void addEventId(String eventId) {
final Set<String> events = getPreferences().getStringSet(MY_EVENTS, new HashSet<String>());
if (events.add(eventId)) {
// Only update the set if it was modified
getEditor().putStringSet(MY_EVENTS, events).apply();
}
}
public static Set<String> getEventIds() {
return getPreferences().getStringSet(MY_EVENTS, new HashSet<String>());
}
}
Basically, this avoids you having to always have a Context on hand to use SharedPreferences. Instead, it always retains a reference to the application context (provided you initialize it in Application.onCreate()).
You can check out how to use SharedPreferences properly here and check another example on the Android docs.
EDIT: As to your design question, it really shouldn't matter to have a static class or not.
Your SharedPreferences are shared throughout the app, and although you can create multiple SharedPreferences objects, they will essentially store and save to the same part of your app as if you just used one object.
It's just something that puzzles me. Is it possible to use the current instance of the class within the constructor?
I've created a BroadcastReceiver that registers itself with the context within the constructor of the BroadcastReceiver. In addition it will unregister again. Is this good style?
Here's my example:
public class MyBroadcastReceiver extends BroadcastReceiver {
protected Context context;
protected MyOnBroadcastReceivedListener listener;
protected int receiverId;
protected String receiverTag;
public MyBroadcastReceiver(int receiverId, Context context, MyOnBroadcastReceivedListener listener, String receiverTag) {
super();
this.context = context;
this.listener = listener;
this.receiverId = receiverId;
this.receiverTag = receiverTag;
IntentFilter intentFilter = new IntentFilter(receiverTag);
context.registerReceiver(this, intentFilter); // <--- Look at the use of this here
}
public void detach() {
if (context != null) {
context.unregisterReceiver(this); // <--- Look at the use of this
}
}
#Override
public void onReceive(Context context, Intent intent) {
// ...
if (listener != null) {
listener.onBroadcastReceived(receiverId, "Bla", "Blub");
}
}
}
Yes, no trouble at all.
Inside the constructor, the object has been created but still no reference has been returned to the rest of the java code. You can use this without worries.
Anyway, in some frameworks where some attributes may be initialized automatic (Context Dependent Injection, CDI), it is not possible to fully initialize the class in the constructor (because such attributes are still not available and may be needed). These frameworks rely in that you mark a method as #PostConstruct; after all attributes are set that method will be called (just so you know what it means when you find it).
If you refer to using this in constructor code, then yes - it is perfectly valid, otherwise constructor would not be really able to construct to much within own instance. I'd however suggest following common practice and prefix your class members (most commonly used prefix is 'm') which helps avoid problems which are sometimes hard to debug. So instead of:
protected Context context;
protected MyOnBroadcastReceivedListener listener;
you would have:
protected Context mContext;
protected MyOnBroadcastReceivedListener mListener;
You can do this, but is not a good style. Passing this from inside a class constructor is dangerous as the current, still constructing object might not be fully intialized.
For example, you might one day add a new int field to the MyBroadcastReceiver, but overlook that you have the statement context.registerReceiver(this, intentFilter); and add the intialization of the new field at the end of the constructor:
public MyBroadcastReceiver(int receiverId, Context context, MyOnBroadcastReceivedListener listener, String receiverTag) {
super();
this.context = context;
this.listener = listener;
this.receiverId = receiverId;
this.receiverTag = receiverTag;
IntentFilter intentFilter = new IntentFilter(receiverTag);
context.registerReceiver(this, intentFilter); // <--- Look at the use of this here
this.newField = 1;
}
Now, you might expect that in the Context.registerReceiver method the newField to be 1 as it initialized in the MyBroadcastReceiver constructor. But you will get the value 0.
See also the following SO question for more information and more potential problems that could appear: Passing "this" in java constructor
Yes it works. I tried a simple test case. and it works. :
public class Test {
private int variable;
private Test2 test2;
public Test(int variable, Test2 test2) {
this.variable = variable;
this.test2 = test2;
test2.printTest(this);
}
public int getVariable() {
return variable;
}
public static void main(String[] args) {
Test test = new Test(111111,new Test2());
}
}
class Test2{
Test2() {
}
public void printTest(Test test){
System.out.println(test.getVariable());
}
}
And it works like a charm