Equality of instance of functional interface in java [duplicate]

落爺英雄遲暮 提交于 2019-12-22 04:13:17

问题


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!


回答1:


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


来源:https://stackoverflow.com/questions/30159677/equality-of-instance-of-functional-interface-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!