I am not sure how I can be sure about equality/immutability of functional interface. I guess there might be no way to assure equality when I use this syntactic sugar in java 8, please let me know any hint if you have any.
I made a short code snippet for my question.
public interface Element {
void doSomething(int a);
}
and I've tried to add instance of this interface in functional way
public class FunctionSet {
public void doubleUp(int a) {
System.out.println(a*2);
}
public void square(int a) {
System.out.println(a*a);
}
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
FunctionSet functionSet = new FunctionSet();
set.add(functionSet::doubleUp);
set.add(functionSet::square);
System.out.println(set.add(functionSet::doubleUp));
}
}
it prints true which means there were not any equality check and also I can't remove any instance from Set once I add it.
in case I use functional interface as an argument, Is there any way that I can compare those instance somehow?
will appreciate any help, thanks in advance!
You can store your method reference into a variable:
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
FunctionSet functionSet = new FunctionSet();
Element fn = functionSet::doubleUp;
set.add(fn);
set.add(functionSet::square);
System.out.println(set.add(fn));
}
This way it returns false.
When you create the same labmda or method reference in different code locations, it's roughly the same as you would create a new anonymous class in both positions:
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
FunctionSet functionSet = new FunctionSet();
set.add(new Element() {
@Override
public void doSomething(int a) {
functionSet.doubleUp(a);
}
});
set.add(new Element() {
@Override
public void doSomething(int a) {
functionSet.square(a);
}
});
System.out.println(set.add(new Element() {
@Override
public void doSomething(int a) {
functionSet.doubleUp(a);
}
}));
}
So every time it's a different object, though it may look the same. For every encountered method reference separate anonymous class is created at the runtime:
Element e1 = functionSet::doubleUp;
Element e2 = functionSet::doubleUp;
System.out.println(e1.getClass());
System.out.println(e2.getClass());
The output will be like this:
class FunctionSet$$Lambda$1/918221580
class FunctionSet$$Lambda$2/1554547125
So practically it's two distinct objects of two distinct classes. It would be quite difficult to conclude that they do the same thing without comparing their bytecode. Also note that they both capture the functionSet
variable, so it should also be ensured that it wasn't changed between two method references.
The only workaround I can think up is to declare all the method references as constants in your code and later reference them instead of using method references directly:
public static final Element FN_DOUBLE_UP = new FunctionSet()::doubleUp;
public static final Element FN_SQUARE = new FunctionSet()::square;
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
set.add(FN_DOUBLE_UP);
set.add(FN_SQUARE);
System.out.println(set.add(FN_DOUBLE_UP));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With