Can I avoid retrolambdas capturing the reference to the enclosing class? - java

I implemented history by letting my forms to implement reconstructor, which is a lambda-returning method. It can be as simple as
#Override protected Supplier<MpxForm> reconstructor() {
return () -> new MyForm1();
}
or more complicated like e.g.,
#Override protected Supplier<MpxForm> reconstructor() {
State currentState = this.currentState;
Set<Item> selectedItems = this.selectedItems;
return () -> new MyForm2(currentState, selectedItems);
}
None of the lambdas needs access to the enclosing instance. That's important as it allows the form to be garbage collected.
However, with retrolambdas, they get converted to an inner class and as I was told, they use this as a reference to their surrounding class so they have a reference to their parent just like non-static inner classes.
This is unnecessary and IIUIC, retrolambda can do it right:
Lambda expressions are backported by converting them to anonymous inner classes. This includes the optimization of using a singleton instance for stateless lambda expressions to avoid repeated object allocation.
Obviously, the lambda in my first snippet is stateless, nonetheless, it was converted to a class having an instance variable of type MyForm1. The above optimization is missing.
The lambda in my second snippet has two instance variables and needs no reference to the enclosing class, so it could be converted to a nested class like
#RequiredArgsConstructor static class MyForm2$Lambda1 implements Runnable {
private final State currentState;
private final Set<Item> selectedItems;
#Override public void run() {
return new MyForm2(currentState, selectedItems);
}
}
Any chance to fix this?

Related

Accessing Same Class' enum value inside an enum declaration within a lambda doesn't compile

I am trying to access an enum value inside the declaration of another enum value in the same class. Following is the way I found to get that done .
Java enum- Cannot reference a field before it is defined
which compiles just fine but since it involves a lot of formal code, I tried to replace the interface implementations with a Lambda but it doesn's compile with an error such as
Cannot reference a field before it is defined
Following is the lambda replacement I did.
package test;
public enum Baz {
yin(() -> {
return Baz.yang;//doesnt compile. ->Cannot reference a field before it is defined
}),
yang(new OppositeHolder() {
#Override
public Baz getOpposite() {
return yin;
}
}),
good(new OppositeHolder() {
#Override
public Baz getOpposite() {
return evil;//BUT THIS COMPILES JUST FINE, EVEN THOUGH IT ACCESSES evil WHICH HAS BEEN DECLARED LATER.
}
}),
evil(new OppositeHolder() {
#Override
public Baz getOpposite() {
return good;
}
});
private final OppositeHolder oppositeHolder;
private Baz(OppositeHolder oppositeHolder) {
this.oppositeHolder = oppositeHolder;
}
private static interface OppositeHolder {
public Baz getOpposite();
}
}
Is there any way I could do this with the help of lambda expressions, since I could be seeing a lot of enums in this class and i don't really want to repeat the boiler plate code.
EDIT
I know that the error means that I cannot access an Enum that has been declared later. Also, I cannot really have the enum name stored as a string since that would be a maintenance nightmare for me. Also, I am curious why the example in the link compiles but mine does not.
This cannot be done by simply replacing anonymous interface implementations by corresponding lambda expressions, because they are not the same thing.
A lambda body does not have its own context. This is defined in the Java Language Specification, ยง 15.27.2:
Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).
(Emphasis mine)
That means you have effectively the same problem as the OP of your linked question.
I doubt if I would follow your approach. I personally prefer the code from this answer.
enum Baz {
YIN,
YANG,
GOOD,
EVIL;
private static final Map<Baz, Baz> OPPOSITES;
static {
Map<Baz, Baz> m = new EnumMap<>(Baz.class);
m.put(YIN, YANG);
m.put(YANG, YIN);
m.put(GOOD, EVIL);
m.put(EVIL, GOOD);
OPPOSITES = Collections.unmodifiableMap(m);
}
public Baz opposite() {
return Objects.requireNonNull(OPPOSITES.get(this));
}
}
the issue is that your using variable before they are defined even if it's a lambda call. A workaround can be to use valueOf
public enum Baz {
yin(() -> Baz.valueOf("yang")),
yang(() -> Baz.valueOf("yin")),
good(() -> Baz.valueOf("evil")),
evil(() -> Baz.valueOf("good"))
;
private final OppositeHolder oppositeHolder;
private Baz(OppositeHolder oppositeHolder) {
this.oppositeHolder = oppositeHolder;
}
private static interface OppositeHolder {
public Baz getOpposite();
}
}
public static void main(String... args){
System.out.println(Baz.yin);
System.out.println(Baz.yin.oppositeHolder.getOpposite());
}
output is
yin
yang

Initializing a static Java constant from a non-thread-safe method

Let there be a class definition like
public static class Bootstrapper {
public static final Object DEFAULT_VALUE = getDefaultValue();
private static Object getDefaultValue() {
if (DEFAULT_VALUE == null) {
return createValue(); // Not thread safe
}
return DEFAULT_VALUE;
}
}
where the createValue() method does not reference the DEFAULT_VALUE field, is only otherwise called in the constructor of the Bootstrapper class and is not thread safe.
Is there any issue (aside from programming style) with the above code? Presumably thread safety is not a problem, given the rules for class initialization, but anything important for the programmer to be aware of?
As Augusto explains, your code is thread-safe. But it's rather convoluted. It would be functionally equivalent, slightly more efficient, and much clearer to simply do this:
public static class Bootstrapper {
private static final Object DEFAULT_VALUE = createValue();
public static Object getDefaultValue() {
return DEFAULT_VALUE;
}
}
Edit: I also just noticed that the field was public and the getter was private. That should probably be the other way around.
This is safe from a threading point of view, as the class loading is thread safe and that value will be set (so getDefaultValue()) will be called after the class is loaded, but before it leaves the class loading code.
To answer PNS comment on the original question above, if the class is loaded by 2 different classloaders you are in trouble anyway, as using the synchronized keyword on getDefaultValue() will create a lock on the class... and since you have 2 classes, each one will be fully independent. You can read this in the Java Language Specification, section 4.3.4 When Reference Types Are the Same (for JLS 8).

No enclosing instance of (class here) is accessible

I have a class called GreenhouseControls that has a bunch of
classes built into it such as:
public class ThermostatNight extends Event {
public ThermostatNight(long delayTime) {
super(delayTime);
}
public void action() {
// hardware control code here.
thermostat = "Night";
}
public String toString() {
return "Thermostat on night setting";
}
}
I pull values from a text file to get event names such as "ThermostatNight" and time values such as "2000". To instantiate a new object with those values I built a EventFactory that accepts the values as arguments.
This is the class I have built to create new event objects from text file values:
public class EventFactory{
public static Event createSpecificEvent(String eventName, long delayTime) {
Event event = null;
switch(eventName) {
case "ThermostatNight":
event = new ThermostatNight(delayTime); // Compiler error
break;
case "ThermostatDay":
event = new ThermostatDay(delayTime);
break;
case "LightOn":
event = new LightOn(delayTime);
break;
case "LightOff":
event = new LightOff(delayTime);
break;
...
}
}
Everything was working well when I ran the program until I pulled the EventFactory class out of GreenhouseControls and into it's own independent class. Now I am getting a compile time error that says:
"No enclosing instance of type GreenhouseControls is accessible. Must
qualify the allocation with an enclosing instance of type
GreenhouseControls (e.g. x.new A() where x is an instance of
GreenhouseControls)."
See in-line comment in EventFactory class to see where the error occurs at "new ThermostatNight(delayTime)"
Your classes are currently inner classes, which need to be constructed in the context of instances of the containing class. Your options are:
Specify an instance of the outer class when constructing an instance of the inner class
Declare your nested classes as static classes, at which point they won't be inner classes any more
Move the nested classes out of the containing class, making them top level classes
Personally I'd go for the last option if possible - nested classes can be useful at times, but you should only use them when there's a real benefit. There are various restrictions which can be quite subtle and which are best avoided if possible. Do you have any compelling reason to make these nested classes?
The error means that a non-static inner class ThermostatNight is being instantiated from a static method. You need to make the class static (the most likely solution given your code), make the method non-static, or provide an instance explicitly.
public static /*<<==Add this*/ class ThermostatNight extends Event {
public ThermostatNight(long delayTime) {
super(delayTime);
}
public void action() {
// hardware control code here.
thermostat = "Night";
}
public String toString() {
return "Thermostat on night setting";
}
}
To provide an instance explicitly, use this example:
public static Event createSpecificEvent(GreenhouseControls ctrl, String eventName, long delayTime) {
Event event = null;
switch(eventName) {
case "ThermostatNight":
event = ctrl.new ThermostatNight(delayTime);
...
}

Exposing instance constants with non-static public final variables

I never see this kind of constants declaration in any Java code around me...
So i'd like to know if you see any drawback of using non-static final constants.
For exemple, i've declared a Guava function as a public constant of a given MaintenanceMode instance. I think it's better because if i created a getDecoratorFunction() it would create a new function instance each time...
Or the get function could return the single instance function that is kept private in the class, but it hads useless code... When we declare constants at class level, we declare directly the constants being public, we do not put them private and provide a public getter to access them...
public class MaintenanceMode {
/**
* Provides a function to decorate a push service with the appropriate decorator
*/
public final Function<PushService,PushService> MAINTENANCE_DECORATION_FUNCTION = new Function<PushService,PushService>() {
#Override
public PushService apply(PushService serviceToDecorate) {
return new PushServiceMaintenanceDecorator(serviceToDecorate,MaintenanceMode.this);
}
};
private final EnumMaintenanceMode maintenanceMode;
private final long milliesBetweenMaintenances;
private final Optional<ExecutorService> executorService;
public EnumMaintenanceMode getMaintenanceMode() {
return maintenanceMode;
}
public long getMilliesBetweenMaintenances() {
return milliesBetweenMaintenances;
}
public Optional<ExecutorService> getExecutorService() {
return executorService;
}
private MaintenanceMode(EnumMaintenanceMode maintenanceMode, long milliesBetweenMaintenances, ExecutorService executorService) {
Preconditions.checkArgument(maintenanceMode != null);
Preconditions.checkArgument(milliesBetweenMaintenances >= 0);
this.maintenanceMode = maintenanceMode;
this.milliesBetweenMaintenances = milliesBetweenMaintenances;
this.executorService = Optional.fromNullable(executorService);
}
}
And i can access this variable with:
pushServiceRegistry.decoratePushServices(maintenanceMode.MAINTENANCE_DECORATION_FUNCTION);
I guess it could lead to strange behaviours if my maintenanceMode was mutable and accessed by multiple threads, but here it's not.
Do you see any drawback of using this kind of code?
Edit: I can have multiple instances of MaintenanceMode, and all instances should be able to provide a different constant function according to the MaintenanceMode state. So i can't use a static variable that would not access the MaintenanceMode state.
The point of a getter would be dynamic dispatch. If you have no need for it, using a public final field is perfectly fine. I even routinely write bean-like objects that have no getters, just public final fields.
By making a constant non-static, you are basically saying that the constant can only be accessed when you have an instance of that class. But it is public (in the case of MAINTENANCE_DECORATION_FUNCTION) and it is part of that class so why not make it static? The constant is, after all, a constant and it does not require an instance of that class to be used elsewhere. The variable maintenanceMode is fine as it is a private constant.

Anonymous innerclass declaration for an instance attribute, using another instance attribute

When using an anonymous innerclass inside a method, when we want to use a method parameter inside the anonymous innerclass, we must mark it as final.
Some details here:
Why do we use final keyword with anonymous inner classes?
But what happens when using a class attribute and not a method local attribute?
Simple usecase: a Spring service with a Guava function:
protected LovValueDAO lovValueDAO;
private final Function<String,LovValue> LOV_ID_TO_LOV = new Function<String,LovValue>() {
#Override
public LovValue apply(String input) {
return lovValueDAO.findById(input);
}
};
#Required
public void setLovValueDAO(LovValueDAO lovValueDAO) {
this.lovValueDAO = lovValueDAO;
}
Is it secure to declare such a Guava function?
According to my tests it works fine but what happens behind the hood?
The initialization order is:
Function is initialized
lovValueDAO is injected by spring through the
setter
Thus i guess, as the function is initialized first, that the lovValueDAO attribute used inside the function will not be a copy of the reference but the reference itself since once the DAO is really injected it works fine.
Am i correct?
And what happen if i use this code:
private final Function<String,LovValue> LOV_ID_TO_LOV = new Function<String,LovValue>() {
#Override
public LovValue apply(String input) {
return lovValueDAO = null;
}
};
Will my outside attribute protected LovValueDAO lovValueDAO; be set to null after i call the function?
Inner class holds an implicit reference to this of its enclosing instance (i.e. an instance of its declaring class in context of which it was created), so that access to fields of the declaring class is treated as a normal field access by that reference.
So, your inner class will see the current value of the field, and can change it as well.

Categories

Resources