Java 8 or Java 11 - I load a static functional interface through an enum constructor. Then I try to compare against the same member reference. Either the code won't compile, or the comparison against the same functional interface fails. Comparisons using .equals, and ==, and comparing .hashcode() all fail. I have created the following POJO Test that demonstrates the issue and points out the specific points in question. I want to code "If instance-member is equal to specific-static-functional-interface-method-x, then do ..."
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import java.util.function.Function;
import org.junit.jupiter.api.Test;
enum MethodReferenceEnum {
One("One", MethodReferenceInterface::one),
Two("Two", MethodReferenceInterface::two);
public String name;
public Function<String, Integer> method;
private MethodReferenceEnum(String aName, Function<String, Integer> aMethod) {
name = aName;
method = aMethod;
}
}
interface MethodReferenceInterface {
public static Integer one(String aString) {
return 1;
}
public static Integer two(String aString) {
return 2;
}
}
class MethodRererencesTest {
@Test
void LocalUseTest() {
// This performs in JavaSE-8 (jdk-1.8.0_271) and JavaSE-11 (jdk-11.0.11).
// These succeed in placing the member references in variables.
Function<String, Integer> choice1a = MethodReferenceInterface::one;
Function<String, Integer> choice1b = MethodReferenceEnum.One.method;
Function<String, Integer> choice2a = MethodReferenceInterface::two;
// These succeed in executing the member references from variables.
assertEquals(1, choice1a.apply("A").intValue());
assertEquals(1, choice1b.apply("B").intValue());
assertEquals(2, choice2a.apply("2nd").intValue());
// Why does the following fail to compile?
//
// assertEquals(choice1a, MethodReferenceInterface::one);
//
// ^ assertEquals fails to compile due to:
// The method assertEquals(Object, Object) in the type Assert is not applicable
// for the arguments (Function<String, Integer), MethodReferenceInterface::one)
// ^ MethodReferenceInterface::one fails to compile due to:
// The target type of the expression must be a functional interface
// Compiles and succeeds; expected.
assertEquals(choice1a, choice1a);
// This compiles, and succeeds,
// but why do they not compare equal?
assertNotEquals(choice1a, choice1b);
}
}
The last line and question sum up the issue. I ran the test above and it passed. The issue is that the variables that house the same member references are not comparing equal. This occurs in Java 8 and Java 11.
When you type:
Function<String, Integer> choice1a = MethodReferenceInterface::one
the compiler converts it to:
Function<String, Integer> choice1a = new Function<>() {
String apply(Integer n) {
return 1;
}
}
It knows to convert it to Function
interface and not anything else because of the type of the member choice1a
.
The function assertEquals
is not a generic function and the input of it is
object
, object
. Therefore the compiler does not know how to create MethodReferenceInterface::one
.
The first parameter of the function choice1a
does not make the function generic equals (aka assertEquals(Function, Function)
) but it makes it
assertEquals(object, object)
.
// This compiles, and succeeds, // but why do they not compare equal? assertNotEquals(choice1a, choice1b);
They are not equal the same reason I specified at first. Each time you use ::
short cut, you create a new instance behind the hood and their references are different.