Почему Java 8 представила новый оператор "::" для ссылок на методы?
В Java 8 ссылки на методы выполняются с помощью оператора ::
.
Пример
// Class that provides the functionality via it static method
public class AddableUtil {
public static int addThemUp(int i1, int i2){
return i1+i2;
}
}
// Test class
public class AddableTest {
// Lambda expression using static method on a separate class
IAddable addableViaMethodReference = AddableUtil::addThemUp;
...
}
Вы можете видеть, что addableViaMethodReference
теперь действует как псевдоним AddableUtil::addThemUp
. Таким образом, addableViaMethodReference()
выполнит то же действие, что и AddableUtil.addThemUp()
, и вернет то же значение.
Почему они решили ввести новый оператор вместо использования существующего? Я имею в виду, выполните функцию, когда имя функции заканчивается на ()
и возвращает ссылку на функцию, если нет конечного ()
.
Выполнение метода
AddableUtil.addThemUp();
Ссылка на метод
AddableUtil.addThemUp;
Разве это не было бы намного проще и интуитивно понятным? AFAIK, AddableUtil.addThemUp
в настоящее время (Java 7) не используется для других целей и генерирует ошибку компиляции. Почему бы не использовать эту возможность вместо создания совершенно нового оператора?
Ответы
Ответ 1
Следующий фрагмент кода отлично компилируется в Java 8, но он будет неоднозначным без нового оператора:
import java.util.function.IntBinaryOperator;
public class A {
public static IntBinaryOperator addThemUp;
public static int addThemUp(int i1, int i2) {
return i1 + i2;
}
public static void main(String[] args) throws Exception {
IntBinaryOperator operator = A::addThemUp;
}
}
Неясно, относится ли A.addThemUp
к общедоступному полю IntBinaryOperator
или пытается создать ссылку на метод.
Да, это немного надуманно. Но вы не можете разрешать случаи краев в синтаксисе языка программирования.
Ответ 2
Поля и методы имеют отдельные пространства имен, поэтому существует возможность двусмысленности между именем метода и именем поля (для чего может потребоваться еще больше правил для устранения неоднозначности). Это определенно большая проблема для подхода "повторно использовать какой-то существующий синтаксис" (который был, BTW, рассмотрен как кандидат, а также ряд других возможностей.)
Но я бы поставил вопрос: "перегружает" существующий синтаксис, как это действительно хорошая идея? (Ваш вопрос предполагает это, но это огромное предположение.) Существует большая разница между "методом вызова m/read field f" и "ссылаться на метод m/field f по имени". Разве два вида выражений не выглядят иначе? Какая польза от повторного использования существующего синтаксиса означает нечто совершенно иное?
Кроме того, существует проблема масштабируемости с предложенным вами подходом: мы никогда не сможем использовать ссылки на поле в будущем, не изобретая новый синтаксис, который тогда будет отличаться от синтаксиса ссылок на методы. Хотя ссылки на поле не были обязательными для лямбды, никогда не быть в состоянии закончить работу здесь было бы большим минусом.
Это лишь некоторые из различных соображений, которые были включены в это решение. Оглядываясь назад, я все еще думаю, что мы сделали правильный звонок здесь.
Ответ 3
Может быть, они сделали это, чтобы заставить программистов на С++ больше приветствовать на Java?/* На мой взгляд (опасные слова для использования в качестве скептика), оператор:: более естественно использовать для статических методов, так как это оператор разрешения области в С++ */