If you make an anonymous class inside a function, and attempt to use an argument inside the static class, then javac/your IDE will throw an error saying that you cannot use a variable inside an anonymous class unless it is declared final....yet all arguments are effectively final due to java's pass reference by value semantics. So why don' the same semantics apply here?
E.g. Error:
public static Optional<Node> getLayerByName(String name) {
Optional<Node> optional = FluentIterable.from(someCollection).firstMatch(new Predicate<Node>() {
@Override
public boolean apply(Node node) {
return name.equals(node.getProperty(LayerProperties.NAME.name()));
}
});
}
But this is fine:
public static Optional<Node> getLayerByName(final String name) {
Optional<Node> optional = FluentIterable.from(someCollection).firstMatch(new Predicate<Node>() {
@Override
public boolean apply(Node node) {
return name.equals(node.getProperty(LayerProperties.NAME.name()));
}
});
}
As far as I know this is the only time that Javac will force to you declarer a function argument as final. There have been many questions on SO about whether its right to declare arguments as final, given that they are effectively final due to java's scoping rules. And its generally considered bad practice to change an argument reference inside the scope of a function anyway.
I am just curious about why the design choice to force you to declare it final, as if it would be confusing in this instance to change the reference inside function scope while the anonymous class uses the function argument, yet it is not considered confusing enough to automatically declare all function references as final.
EDIT - This is a question about Java's choice of semantics, not a question about why the variable has to be final.
E.g. for lots of programmers from a non java background might expect
public static changeReference(String thing){
thing = "changed";
}
public static void main(String[] args) {
String thing = "orgininal";
changeReference(thing)
System.out.println(thing); //prints original
}
to actually print "changed". In this sense all references in arguments are final, in that nothing which changes the reference inside a function affects the reference outside of the function. It seems like it would improve clarity if we just always put final in, then it would be clear that the changeReference function doesn't do anything because the compiler would tell you. But if you are to allow the local rescoping of argument variables, is this really any more or less confusing than if:
public static Optional<Node> getLayerByName(String name, Collection<Node> someCollection) {
name = "changed"
Optional<Node> optional = FluentIterable.from(someCollection).firstMatch(new Predicate<Node>() {
@Override
public boolean apply(Node node) {
System.out.println(name);
return name.equals(node.getProperty(LayerProperties.NAME.name()));
}
});
}
public static void main(Collection<Node> someCollection){
getLayerByName("original", someCollection); // prints "original" never "changed"
}
was allowed an prints "original" rather than changed? Why did the designer's think one of these behaviours was more confusing than the other and force extra semantics on you to deal with it, or why did they not enforce the same semantics in these two virtually identical situations?