Я экспериментирую с Java 8, чтобы понять, как он функционирует как первоклассный гражданин. У меня есть следующий фрагмент:
package test;
import java.util.*;
import java.util.function.*;
public class Test {
public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
list.forEach(functionToBlock(myFunction));
}
public static void displayInt(Integer i) {
System.out.println(i);
}
public static void main(String[] args) {
List<Integer> theList = new ArrayList<>();
theList.add(1);
theList.add(2);
theList.add(3);
theList.add(4);
theList.add(5);
theList.add(6);
myForEach(theList, Test::displayInt);
}
}
Я пытаюсь передать метод displayInt
методу, myForEach
используя ссылку на метод. Компилятор выдает следующую ошибку:
src/test/Test.java:9: error: cannot find symbol
list.forEach(functionToBlock(myFunction));
^
symbol: method functionToBlock(Function<Integer,Void>)
location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
myForEach(theList, Test::displayInt);
^
required: List<Integer>,Function<Integer,Void>
found: List<Integer>,Test::displayInt
reason: argument mismatch; bad return type in method reference
void cannot be converted to Void
Компилятор на это жалуется void cannot be converted to Void
. Я не знаю, как указать тип интерфейса функции в сигнатуре myForEach
, чтобы код компилировался. Я знаю, что могу просто изменить тип возвращаемого значения displayInt
на, Void
а затем вернуться null
. Однако могут возникнуть ситуации, когда невозможно изменить метод, который я хочу передать в другое место. Есть ли простой способ повторно использовать displayInt
как есть?
Block
Consumer
MethodHandle
), и, используя это, компилятор Java может создавать более эффективный код, например, реализуя лямбда-выражения без закрытия как статические методы, предотвращая тем самым создание дополнительные занятия.Function<Void, Void>
естьRunnable
.Runnable
иCallable
интерфейсам написано , что они должны быть использованы в сочетании с нитями . Досадным последствием этого является то, что некоторые инструменты статического анализа (например, Sonar) будут жаловаться, если вы вызоветеrun()
метод напрямую.Когда вам нужно принять функцию в качестве аргумента, которая не принимает аргументов и не возвращает результата (void), на мой взгляд, все же лучше иметь что-то вроде
public interface Thunk { void apply(); }
где-то в вашем коде. В моих курсах функционального программирования для описания таких функций использовалось слово thunk. Почему этого нет в java.util.function, я не понимаю.
В других случаях я обнаружил, что даже когда в java.util.function есть что-то, что соответствует подписи, которую я хочу, это все равно не всегда правильно, когда именование интерфейса не соответствует использованию функции в моем коде. Я предполагаю, что это то же самое, что и в другом месте здесь, в отношении «Runnable» - термина, связанного с классом Thread - так что, хотя у него может быть нужная мне подпись, она все же может запутать читателя.
источник
Runnable
, не допускаются проверенные исключения, что делает его бесполезным для многих приложений. ПосколькуCallable<Void>
это тоже бесполезно, вам, кажется, нужно определить свое собственное. Некрасиво.Установите тип возврата
Void
вместоvoid
иreturn null
// Modify existing method public static Void displayInt(Integer i) { System.out.println(i); return null; }
ИЛИ
// Or use Lambda myForEach(theList, i -> {System.out.println(i);return null;});
источник
Я считаю, что вам следует использовать пользовательский интерфейс вместо
Function<T, R>
.Потребитель - это, по сути, функциональный интерфейс, предназначенный для принятия значения и ничего не возвращающего (т.е. void).
В вашем случае вы можете создать потребителя в другом месте вашего кода следующим образом:
Consumer<Integer> myFunction = x -> { System.out.println("processing value: " + x); .... do some more things with "x" which returns nothing... }
Затем вы можете заменить свой
myForEach
код приведенным ниже фрагментом:public static void myForEach(List<Integer> list, Consumer<Integer> myFunction) { list.forEach(x->myFunction.accept(x)); }
Вы относитесь к myFunction как к первоклассному объекту.
источник