Как указать типы функций для методов void (не Void) в Java8?
я играю с 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 как это?
2 ответов:
вы пытаетесь использовать неправильный тип интерфейса. Тип функции не подходит в этом случае, потому что он получает параметр и имеет возвращаемое значение. Вместо этого вы должны использовать потребитель (ранее известный как блок)
тип функции объявляется как
interface Function<T,R> { R apply(T t); }однако тип потребителя совместим с тем, что вы ищете:
interface Consumer<T> { void accept(T t); }как таковой, потребитель совместим с методами, которые получите T и ничего не возвращайте (void). И это то, что вы хотите.
например, если бы я хотел отобразить все элементы в списке, я мог бы просто создать для этого потребителя с лямбда-выражением:
List<String> allJedi = asList("Luke","Obiwan","Quigon"); allJedi.forEach( jedi -> System.out.println(jedi) );вы можете видеть выше, что в этом случае лямбда-выражение получает параметр и не имеет возвращаемого значения.
теперь, если я хотел использовать ссылку на метод вместо лямбда-выражения для создания потребления этого типа, то мне нужен метод, который получает строку и возвращает void, верно?.
я мог бы использовать различные типы ссылок на методы, но в этом случае давайте воспользуемся ссылкой на метод объекта с помощью
printlnметод
когда вам нужно принять функцию в качестве аргумента, который не принимает аргументов и не возвращает результата (void), на мой взгляд, все равно лучше иметь что-то вроде
private interface Thunk { void apply(); }где-то в коде. В моих курсах функционального программирования слово "thunk" использовалось для описания таких функций. Почему это не в java.утиль.функция находится за пределами моего понимания.
в других случаях я нахожу, что даже когда java.утиль.функция имеет что-то, что соответствует подписи, которую я хочу - это все еще не всегда правильно, когда имя интерфейса не соответствует использованию функции в моем коде. Я думаю, что это аналогичная точка зрения, которая сделана в другом месте здесь относительно "Runnable" - это термин, связанный с классом Thread - поэтому, хотя он может иметь подпись, которая мне нужна, это все еще, вероятно, смутит читателя.
Comments