Java-эквиваленты Func и Action
Что такое эквиваленты Java Func и Действие?
Я имею в виду, вместо того, чтобы писать это самостоятельно:
public interface Func<TInput, TResult>
{
TResult call(TInput target) throws Exception;
}
public interface Action<T>
{
void call(T target) throws Exception;
}
Ответы
Ответ 1
В Java 8 эквивалентами являются java.util.function.Function<T, R>
и java.util.function.Consumer<T>
соответственно. Аналогично, java.util.function.Predicate<T>
эквивалентно System.Predicate<T>
. Как упоминалось в других местах, это интерфейсы вместо делегатов.
Относится в сторону: в настоящее время я склоняюсь к следующему классу утилиты, чтобы использовать материал метода расширения LINQ:
abstract class IterableUtil {
public static <T> Iterable<T> where(Iterable<T> items, Predicate<T> predicate) {
ArrayList<T> result = new ArrayList<T>();
for (T item : items) {
if (predicate.test(item)) {
result.add(item);
}
}
return result;
}
public static <T, R> Iterable<R> select(Iterable<T> items, Function<T, R> func) {
ArrayList<R> result = new ArrayList<R>();
for (T item : items) {
result.add(func.apply(item));
}
return result;
}
}
В отличие от System.Linq.Enumerable.Where<TSource>
и System.Linq.Enumerable.Select<TSource, TResult>
описанные здесь LINQ-подобные методы не являются ленивыми и полностью пересекают исходные коллекции, прежде чем возвращать коллекции результатов вызывающему. Тем не менее, я считаю их полезными для чисто синтаксических целей и при необходимости может быть ленивым. Учитывая,
class Widget {
public String name() { /* ... */ }
}
Можно сделать следующее:
List<Widget> widgets = /* ... */;
Iterable<Widget> filteredWidgets = IterableUtil.where(widgets, w -> w.name().startsWith("some-prefix"));
Что я предпочитаю:
List<Widget> widgets = /* ... */;
List<Widget> filteredWidgets = new ArrayList<Widget>();
for (Widget w : widgets) {
if (w.name().startsWith("some-prefix")) {
filteredWidgets.add(w);
}
}
Ответ 2
Callable интерфейс похож на Func.
Runnable интерфейс похож на действие.
В общем, Java использует анонимные внутренние классы в качестве замены делегатов С#.
Например, так вы добавляете код для реагирования на нажатие кнопки в GUI:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
...//code that reacts to the action...
}
});
Ответ 3
Элегантность перегруженных делегатов Func (помимо делегирования против анонимного класса) заключается в том, что они поддерживают от 0 до 16 аргументов (Func<TResult>
, Func<T, TResult>
, Func<T1, T2, TResult>
и т.д.)
К сожалению, это невозможно в Java из-за стирания типа. Классы не могут отличаться только параметрами типового типа.
Java 8 теперь вводит зоопарк с именами типа BiConsumer
для Action<T, T2>
и, поскольку Java не допускает примитивных аргументов типа, BiIntConsumer
. "Зоопарк", однако, не очень большой, и я не знаю о библиотеке, которая ее расширяет. Было замечательное предложение для литералов типа функций, таких как (int, int) => void
, но оно не было принято.
Ответ 4
Для них действительно нет эквивалентов. Вы можете создавать анонимные внутренние классы в Java, но обычно существуют определенные интерфейсы, а не такие общие, как Func и Action.
Ответ 5
Java не имеет понятия делегатов. Обходной подход можно найти в Программист Java Посмотрит на делегатов С#:
В то время как С# имеет набор возможностей подобно Java, он добавил несколько новые и интересные функции. Делегирование - это способность рассматривать метод как объект первого класса. С# делегат используется там, где разработчики Java будет использовать интерфейс с одним метод. В этой статье использование делегаты в С#, и код представлен для делегата Java объект, который может выполнять аналогичные функция. Загрузите исходный код здесь.
Ответ 6
Для Func<T>
используйте: java.util.function.Supplier
http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html
Ответ 7
Вы можете использовать java.util.Function, как это
Function<Employee, String> f0 = (e) -> e.toString();
Но если вы хотите использовать его с более чем одним аргументом (как это делает С# Func), то вы должны определить свою версию FunctionalInterface следующим образом
@FunctionalInterface
public interface Func2Args<T, T1, R> {
R apply(T t, T1 t1);
}
@FunctionalInterface
public interface Func3Args<T,T1,T2,R> {
R apply(T t, T1 t1, T2 t2);
}
Тогда вы можете использовать с переменной no аргументов
Func2Args<Employee,Employee,String> f2 = (e, e2) -> e.toString() +
e2.toString();
Func3Args<Employee,Employee,Employee,String> f3 = (e, e2, e3) ->
e.toString() + e2.toString() + e3.toString();
Ответ 8
Для более старых версий, чем Java 8
Для обратных вызовов методов в С#, которые я использовал следующим образом:
public void MyMethod(string par1, string par2, Action<int> callback, Action<int, string> callback2)
{
//Async Code
callback.invoke(1);
callback2.invoke(4, "str");
}
и называя это:
utils.MyMethod("par1", "par2", (i) =>
{
//cb result
}, (i, str) =>
{
//cb2 result
});
Я сделал небольшие абстрактные классы в Java
package com.example.app.callbacks;
public abstract class Callback1<T> {
public void invoke(T obj) {}
}
package com.example.app.callbacks;
public abstract class Callback2<T, T2> {
public void invoke(T obj, T2 obj2) {}
}
package com.example.app.callbacks;
public abstract class Callback3<T, T2, T3> {
public void invoke(T obj, T2 obj2, T3 obj3) {}
}
...ETC
Java-метод выглядит так:
public void myMethod(String par1, String par2, final Callback1<int> callback, final Callback2<int, String> callback2) {
//Async Code
callback.invoke(1);
callback2.invoke(4, "str");
}
Теперь при вызове в Java:
utils.myMethod("par1", "par2", new Callback<int>() {
@Override
public void invoke(int obj) {
super.invoke(obj);
//cb result
}
}, new Callback2<int, String>() {
@Override
public void invoke(int obj, String obj2) {
super.invoke(obj, obj2);
//cb2 result
}
});
Это также работает, передавая/устанавливая ваши обратные вызовы для классов, в которых вы хотите их вызывать, тот же метод можно использовать и для создания интерфейсов:
package com.example.app.interfaces;
public interface MyInterface<T> {
void makeDo(T obj);
void makeAnotherDo();
}