Какие эквиваленты Java для Func и Action ?
Я имею в виду, вместо того, чтобы писать это самостоятельно:
public interface Func<TInput, TResult>
{
TResult call(TInput target) throws Exception;
}
public interface Action<T>
{
void call(T target) throws Exception;
}
Ответы:
В 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); } }
источник
Function<T, R>
иConsumer<T>
вы можете найти полный набор общих функциональных интерфейсов, Java предоставляет здесь .Вызываемый интерфейс похож на Func.
Runnable интерфейс похож на Action.
В общем, Java использует анонимные внутренние классы в качестве замены делегатов C #. Например, вот как вы добавляете код для реакции на нажатие кнопки в графическом интерфейсе:
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ...//code that reacts to the action... } });
источник
Элегантность перегруженных делегатов Func (помимо делегата против анонимного вопроса класса) является то , что они поддерживают от 0 до 16 аргументов (
Func<TResult>
,Func<T, TResult>
,Func<T1, T2, TResult>
и т.д.)К сожалению, в Java это невозможно из-за стирания типа. Классы не могут различаться только параметрами универсального типа.
Java-теперь приносит в зоопарке имен , как
BiConsumer
дляAction<T, T2>
и, поскольку Java не позволяет аргументы примитивного типа,BiIntConsumer
. Однако «зоопарк» не очень большой, и я не знаю библиотеки, которая бы его расширяла. Было прекрасное предложение для литералов функционального типа,(int, int) => void
но оно не было принято.источник
Func`1
и т.д. Просто C # отображает их на одно и то же имя.BiConsumer
дляAction<T, T2>
и, поскольку Java не позволяет параметры примитивного типа,BiIntConsumer
. Было предложение о литералах типа функции,(int, int) => void
но оно не было принято.Для
Func<T>
использования: java.util.function.Supplier http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.htmlисточник
Supplier
будет эквивалентноFunc<T>
(в отличие отFunc<T1, T2>
) notAction
. An неAction
принимает аргументов и не возвращает результата. (Другие версииAction
принимают различное количество аргументов и не возвращают результата.)Func<T>
Java-файл и по ошибке запомнил его какAction<T>
. ОйAction<>
: 0 входов, 0 выходов. В лучшем случае с.andThen(...)
функциональностью.Action<>
на 0 входов и 0 выходов. Но помните, в Java это всего лишь интерфейсы. Итак, вы можете создать свой собственный для использования.Runnable
forAction<>
, хотя его не так удобно использовать, как новые функциональные возможности Java 8.Им действительно нет эквивалентов. Вы можете создавать анонимные внутренние классы в Java, но обычно это специфические интерфейсы, а не такие общие, как Func и Action.
источник
В Java нет концепции делегатов. Обходной подход см. В статье " Программист на Java смотрит на делегатов C #". :
источник
Вы можете использовать java.util.Function, как это
Но если вы должны использовать его с более чем одним аргументом (как это делает C # 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); }
Затем вы можете использовать с переменной без аргументов
источник
Для более старых версий, чем Java 8
Для обратных вызовов методов в C #, которые я использовал так:
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(); }
источник