¿Cuáles son los equivalentes de Func y Action en Java ?
Quiero decir, en lugar de escribir esto por mi cuenta:
public interface Func<TInput, TResult>
{
TResult call(TInput target) throws Exception;
}
public interface Action<T>
{
void call(T target) throws Exception;
}
Respuestas:
En Java 8, los equivalentes son las interfaces
java.util.function.Function<T, R>
yjava.util.function.Consumer<T>
respectivamente. De manera similar,java.util.function.Predicate<T>
es equivalente aSystem.Predicate<T>
. Como se mencionó en otra parte, estas son interfaces en lugar de delegados.Aparte de lo relacionado: actualmente me estoy apoyando en gran medida en la siguiente clase de utilidad para hacer cosas de métodos de extensión similares a 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; } }
A diferencia
System.Linq.Enumerable.Where<TSource>
ySystem.Linq.Enumerable.Select<TSource, TResult>
el LINQ como métodos que presento aquí no son perezosos y atravesar completamente de las colecciones de origen antes de regresar las colecciones de resultados al llamador. Aún así, los encuentro útiles para propósitos puramente sintácticos y podrían volverse perezosos si fuera necesario. Dadoclass Widget { public String name() { /* ... */ } }
Uno puede hacer lo siguiente:
List<Widget> widgets = /* ... */; Iterable<Widget> filteredWidgets = IterableUtil.where(widgets, w -> w.name().startsWith("some-prefix"));
Que prefiero a lo siguiente:
List<Widget> widgets = /* ... */; List<Widget> filteredWidgets = new ArrayList<Widget>(); for (Widget w : widgets) { if (w.name().startsWith("some-prefix")) { filteredWidgets.add(w); } }
fuente
Function<T, R>
yConsumer<T>
, puede encontrar el conjunto completo de interfaces funcionales comunes que proporciona Java aquí .La interfaz invocable es similar a Func.
Runnable interfaz es similar a Action.
En general, Java usa clases internas anónimas como reemplazo de los delegados de C #. Por ejemplo, así es como agrega código para reaccionar al presionar un botón en la GUI:
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ...//code that reacts to the action... } });
fuente
La elegancia de los delegados Func sobrecargados (además del delegado vs cuestión de clase anónima) es que se apoyan de 0 a 16 argumentos (
Func<TResult>
,Func<T, TResult>
,Func<T1, T2, TResult>
, etc.)Desafortunadamente, esto es imposible en Java debido al borrado de tipos. Las clases no pueden diferir únicamente por parámetros de tipo genérico.
Java 8 ahora trae un zoológico de nombres como
BiConsumer
paraAction<T, T2>
y, a causa de Java no permite argumentos de tipo primitivo,BiIntConsumer
. El "zoológico", sin embargo, no es muy grande y no conozco una biblioteca que lo amplíe. Hubo una propuesta maravillosa para literales de tipo de función como,(int, int) => void
pero no fue adoptada.fuente
Func`1
etc. Es solo C # el que los asigna al mismo nombre.BiConsumer
paraAction<T, T2>
y, a causa de Java no permite parámetros de tipo primitivo,BiIntConsumer
. Hubo una propuesta para literales de tipo de función como,(int, int) => void
pero no fue adoptada.Para
Func<T>
usar: java.util.function.Supplier http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.htmlfuente
Supplier
sería equivalente aFunc<T>
(en contraposición aFunc<T1, T2>
) noAction
. AnAction
no acepta argumentos y no devuelve ningún resultado. (Otras versiones deAction
aceptan varios números de argumentos y no devuelven ningún resultado.)Func<T>
para Java y lo recordé por error comoAction<T>
. VayaAction<>
: 0 entradas, 0 salidas? En el mejor de los casos con.andThen(...)
funcionalidad.Action<>
con 0 entradas y 0 salidas. Pero recuerde, en Java estas son solo interfaces. Por lo tanto, puede crear el suyo propio para usar.Runnable
paraAction<>
, aunque no es tan bonito de usar como el nuevo material funcional de Java 8.Realmente no hay equivalentes para esos. Puede crear clases internas anónimas en Java, pero tiende a haber interfaces específicas en lugar de genéricas como Func y Action.
fuente
Java no tiene el concepto de delegados. Para obtener una solución alternativa, consulte Un programador de Java observa a los delegados de C # :
fuente
Puede usar java.util.Function así
Pero si va a usarlo con más de un argumento (como lo hace C # Func), entonces debe definir su versión de FunctionalInterface de la siguiente manera
@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); }
Entonces puedes usar con variable no de argumentos
fuente
Para versiones anteriores a Java 8
Para devoluciones de llamada de método en C # que utilicé así:
public void MyMethod(string par1, string par2, Action<int> callback, Action<int, string> callback2) { //Async Code callback.invoke(1); callback2.invoke(4, "str"); }
y llamarlo:
utils.MyMethod("par1", "par2", (i) => { //cb result }, (i, str) => { //cb2 result });
He realizado pequeñas clases abstractas en 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
El método Java se ve así:
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"); }
Ahora, al llamarlo en 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 } });
Esto también funciona al pasar / configurar sus devoluciones de llamada a las clases en las que desea llamarlas, el mismo método también se puede usar para crear interfaces:
package com.example.app.interfaces; public interface MyInterface<T> { void makeDo(T obj); void makeAnotherDo(); }
fuente