In Item 71 in 'Effective Java, Second Edition' the Double-check idiom and the single-check idiom are introduced for lazily instantiating instance fields.
Double-check idiom
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) {
synchronized(this) {
result == field;
if (result == null)
field = result = computeFieldValue();
}
}
return result;
}
Single-check idiom
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) {
field = result = computeFieldValue();
}
return result;
}
In the double-check idiom Joshua states, that the result variable is used to make sure that the volatile field is only read once, which improves performance. This I understand, however I don't see why we need it in the single-check idiom, since we only read field once anyway.
In the single-check idiom, without the result variable you'd still be reading it twice; once for the null check and once for the return value.
I prefer the following implementation of lazy evaluation:
#ThreadSafe
class MyClass {
private static class MyClassHelper {
public static final MyClass helper = new MyClass();
}
public static MyClass getInstance() {
return MyClassHelper.helper;
}
}
Related
how do you think, do we need to use synchronized block for better optimization of access to instance of Ad?
The instance of Ad.class can be retrieved from different threads. Synchronized helps to get an instance in one time with one get operation from ConcurrentHashMap. ConcurrentHashMap store all values as volatile. I use it on java 1.7 for android, computeIfAbsent is available in java 1.8.
It will be great to get detailed answer, why not or why yes.
Thank you!
public final class Ad {
private final static Map<String, Ad> ads = new ConcurrentHashMap<>();
public static Ad get(#NonNull String appId) {
if (appId == null) appId = "";
boolean containsAd = ads.containsKey(appId);
Ad localInstance = containsAd ? ads.get(appId) : null;
if (localInstance == null) {
synchronized (Ad.class) {
containsAd = ads.containsKey(appId);
localInstance = containsAd ? ads.get(appId) : null;
if (localInstance == null) {
localInstance = new Ad();
localInstance.setAdId(appId);
ads.put(appId, localInstance);
}
}
}
return localInstance;
}
private Ad() {
}
}
UPDATE: Thanks to all for help. I replaced ConcurrentHashMap to HashMap.
This is not quite optimal. If multiple threads try initialize values at the same time, then they will block each other, even if they are looking for different keys.
You should use ConcurrentHashMap.computeIfAbsent to check for the add and create missing ones in a single step. That way you will not create any Ads that aren't used, and two threads will only block each other if they're trying to initialize the same entry:
public static Ad get(#NonNull String appId) {
if (appId == null) appId = "";
return ads.computeIfAbsent(appId, Ad::new);
}
private Ad(String appId) {
this();
setAdId(appId);
}
From what I understand what you actually want to achieve is putIfAbsent and as such this is much simpler then what you do (your are using a double check locking):
public static Ad get(String appId) {
String newId = appId == null ? "" : appId;
ads.putIfAbsent(newId, new Ad());
return map.get(newId);
}
I have been working with Fields for parsing a class to a SharedPreferences. It worked while the settings class was not a Singleton. I changed to work as a Singleton and it is not working anymore.
G2ASettings settings = G2ASettings.getInstance();
Field[] fields = G2ASettings.class.getDeclaredFields();
for (Field f : fields) {
f.setAccessible(true);
try {
if (preferences.contains(f.getName()) && !f.getName().equals("INSTANCE")) {
f.set(settings, preferences.getBoolean(f.getName(), f.getBoolean(settings))); //si no lo encuentra, pone el valor por defecto determinado en la clase
} else {
if (blablabla) {
editor.putBoolean(f.getName(), true);
allPreferencesDisabled = true;
} else
(*)-----> editor.putBoolean(f.getName(), f.getBoolean(settings));
}
(*)-----> if (!allPreferencesDisabled) allPreferencesDisabled = f.getBoolean(settings);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
The error reported is the following:
Caused by: java.lang.IllegalArgumentException: not a primitive field
The error is repoted at lines marked as (*) in the code.
The fields of G2ASettings are all public and boolean except INSTANCE variable which is G2ASettings type variable and is private.
I will be reporting here my progress.
EXTRA: I post here only relevant data of G2ASettings class (usual Singleton class):
public class G2ASettings implements Serializable {
public boolean {big amount of boolean variables]
private static G2ASettings INSTANCE = null;
private synchronized static void createInstance() {
if (INSTANCE == null) {
INSTANCE = new G2ASettings();
}
}
public static G2ASettings getInstance() {
if (INSTANCE == null) createInstance();
return INSTANCE;
}
{public getters and setters}
}
Which field is the one you're on when it throws this exception? I'd bet money it's INSTANCE, which as you said isn't a Boolean so you can't call getBoolean() on it.
Your if statement that checks if the current field is not INSTANCE before trying to get its Boolean value needs to be earlier and cover all of your other logic, since INSTANCE is never going to have a Boolean value and shouldn't be persisted.
That's how I do it (android code)
private volatile static WifiManager wm;
private static WifiManager wm(Context ctx) {
WifiManager result = wm;
if (result == null) {
synchronized (WifiMonitor.class) { // the enclosing class
result = wm;
if (result == null) {
result = wm = (WifiManager) ctx
.getSystemService(Context.WIFI_SERVICE);
if (result == null) throw new WmNotAvailableException();
}
}
}
return result;
}
Bloch in Effective Java recommends :
// Lazy initialization holder class idiom for static fields
private static class FieldHolder {
static final FieldType field = computeFieldValue();
}
static FieldType getField() {
return FieldHolder.field;
}
This has the advantages of dispensing with the synchronization and that the JVM optimizes out the field access. The problem is that I need a Context object in my case. So :
Is there a way to adapt Bloch's pattern to my case (computeFieldValue() needs a param) ?
If not, is there a way to execute around ? The code is subtle and I'd rather have it in one place and pass only required behavior in
Last but not least - is there a way to enforce access to the cache field (wm) only via the wm() method ? So I can avoid NPEs and such. Other languages use properties for this
You can do the following
static int param1;
static String param2;
public static void params(int param1, String param2) {
this.param1 = param1;
this.param2 = param2;
}
private static class FieldHolder {
static final FieldType field = new FieldType(param1, param2);
}
static FieldType getField() {
return FieldHolder.field;
}
Note: even simpler than this is to use an enum,
enum Singleton {
INSTANCE;
}
or
class SingletonParams {
static X param1;
}
enum Singleton implements MyInterface {
INSTANCE(SingletonParams.param1, ...);
}
I would like to be able to validate the state of the enum to make sure there are no duplicate codes. For example consider the enum below.
public enum UniqueCodes {
A(1), B(2), C(3), D(1);
private final int value;
static {
UniqueCodes[] values = UniqueCodes.values();
Map<Integer, Boolean> map = new HashMap<>();
for (UniqueCodes code : values) {
if (map.get(code.value) == null) {
map.put(code.value, true);
} else {
String msg = String.format(
"%s enum contains a non unique code %s",
UniqueCodes.class.getName(), code.value);
System.err.println(msg);
try {
System.exit(-1);
} catch(SecurityException e) {
System.err.println("Really Bad things are going to happen to the application");
// what can I do here to crash the JVM
}
}
}
}
private UniqueCodes(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
Imagine the above enum with 100+ codes assigned and you want to make sure that no enum definition
contains a duplicate value. If a duplicate value is detected I want to crash the JVM but that is not that is easy to do. Throwing an exception is not effective because a catch(Throwable e) will catch everything.
public class Main {
public static void main(String[] args) {
try {
System.out.println(UniqueCodes.A);
} catch(Throwable e) {
System.out.println("Invalid Enum exception caught");
}
}
}
I can write a unit test to prove that the enum definition is good and there are no duplicate codes. But is there a way to kind of make it self testing and fool proof so that things don't run if the enum does not have unique codes?
A couple of points:
It is simpler to use a set than a map for this.
Throwing an exception out of a class's static block will be effective because it will block the loading of the class. Even if you deliberately catch and ignore the first error with a catch (Throwable t), any later code which tries to make any use of the "invalid" enum will spontaneously throw a java.lang.NoClassDefFoundError.
I'd write the validation code as follows:
static {
Set<Integer> set = new HashSet<>();
for (UniqueCodes code : values()) {
if (!set.add(code.value)) {
throw new RuntimeException(String.format(
"%s enum contains a non unique code %s",
UniqueCodes.class.getName(), code.value));
}
}
}
P.S. If you don't need any particular value for the unique codes, you should know that Enum.ordinal() exists, which returns the zero-based index of the constant in the order it was defined.
It would be simplest to have the constructor check that the value is unique, like this:
A(1), B(2), C(3), D(1);
// Not initialized until after instances
private static Set<Integer> set = new HashSet<Integer>();
private final int value;
private UniqueCodes(int value) {
// throws NPE
if (!set.add(value))
throw new IllegalArgumentException("Duplicate value: " + value);
this.value = value;
}
but the challenge with enums is that static fields must appear after the instances, and so are not initialized until after all constructors are executed - too late, and you get a NPE when you go to use the set.
Fortunately, there's a work around!
You can use the Initialization-on-demand holder idiom to give you an initialized set before the instances are initialized:
public enum UniqueCodes {
A(1), B(2), C(3), D(1);
private static class Holder {
static Set<Integer> set = new HashSet<Integer>();
}
private final int value;
private UniqueCodes(int value) {
if (!Holder.set.add(value))
throw new IllegalArgumentException("Duplicate value: " + value);
this.value = value;
}
public int getValue() {
return value;
}
}
The reason this works is thanks to the class loader contract, which must initialize all static fields before the class can be used, and the class is loaded when first used. The Holder class is first used in the constructor, and at that point the class loader initializes the set.
To see what happens when you access the enum, see this link.
I'm not sure this is even worth doing for enums like your example. Since you are hardcoding the enum yourself, can't you as the coder just make sure you aren't hardcoding the enum incorrectly?
I have to following code to check whether the entity in my model has a nullable=false or similar annotation on a field.
import javax.persistence.Column;
import .....
private boolean isRequired(Item item, Object propertyId) {
Class<?> property = getPropertyClass(item, propertyId);
final JoinColumn joinAnnotation = property.getAnnotation(JoinColumn.class);
if (null != joinAnnotation) {
return !joinAnnotation.nullable();
}
final Column columnAnnotation = property.getAnnotation(Column.class);
if (null != columnAnnotation) {
return !columnAnnotation.nullable();
}
....
return false;
}
Here's a snippet from my model.
import javax.persistence.*;
import .....
#Entity
#Table(name="m_contact_details")
public class MContactDetail extends AbstractMasterEntity implements Serializable {
#Column(length=60, nullable=false)
private String address1;
For those people unfamiliar with the #Column annotation, here's the header:
#Target({METHOD, FIELD})
#Retention(RUNTIME)
public #interface Column {
I'd expect the isRequired to return true every now and again, but instead it never does.
I've already done a mvn clean and mvn install on my project, but that does not help.
Q1: What am I doing wrong?
Q2: is there a cleaner way to code isRequired (perhaps making better use of generics)?
property represents a class (it's a Class<?>)
#Column and #JoinColumn can only annotate fields/methods.
Consequently you will never find these annotations on property.
A slightly modified version of your code that prints out whether the email property of the Employee entity is required:
public static void main(String[] args) throws NoSuchFieldException {
System.out.println(isRequired(Employee.class, "email"));
}
private static boolean isRequired(Class<?> entity, String propertyName) throws NoSuchFieldException {
Field property = entity.getDeclaredField(propertyName);
final JoinColumn joinAnnotation = property.getAnnotation(JoinColumn.class);
if (null != joinAnnotation) {
return !joinAnnotation.nullable();
}
final Column columnAnnotation = property.getAnnotation(Column.class);
if (null != columnAnnotation) {
return !columnAnnotation.nullable();
}
return false;
}
Note that this is a half-baked solution, because JPA annotations can either be on a field or on a method. Also be aware of the difference between the reflection methods like getFiled()/getDeclaredField(). The former returns inherited fields too, while the latter returns only fields of the specific class ignoring what's inherited from its parents.
The following code works:
#SuppressWarnings("rawtypes")
private boolean isRequired(BeanItem item, Object propertyId) throws SecurityException {
String fieldname = propertyId.toString();
try {
java.lang.reflect.Field field = item.getBean().getClass().getDeclaredField(fieldname);
final JoinColumn joinAnnotation = field.getAnnotation(JoinColumn.class);
if (null != joinAnnotation) {
return !joinAnnotation.nullable();
}
final Column columnAnnotation = field.getAnnotation(Column.class);
if (null != columnAnnotation) {
return !columnAnnotation.nullable();
}
} catch (NoSuchFieldException e) {
//not a problem no need to log this event.
return false;
}
}