Quais são os equivalentes de Java de Func e Action ?
Quer dizer, em vez de escrever sozinho:
public interface Func<TInput, TResult>
{
TResult call(TInput target) throws Exception;
}
public interface Action<T>
{
void call(T target) throws Exception;
}
Respostas:
No Java 8, os equivalentes são as interfaces
java.util.function.Function<T, R>
ejava.util.function.Consumer<T>
respectivamente. Da mesma forma,java.util.function.Predicate<T>
é equivalente aSystem.Predicate<T>
. Conforme mencionado em outro lugar, são interfaces em vez de delegados.Relacionado à parte: Atualmente estou me apoiando fortemente na seguinte classe de utilitário para fazer coisas de método de extensão semelhantes ao 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; } }
Os métodos diferentes
System.Linq.Enumerable.Where<TSource>
eSystem.Linq.Enumerable.Select<TSource, TResult>
semelhantes ao LINQ que apresento aqui não são preguiçosos e percorrem totalmente as coleções de origem antes de retornar as coleções de resultados ao chamador. Ainda assim, eu os considero úteis para propósitos puramente sintáticos e podem se tornar preguiçosos se necessário. Dadoclass Widget { public String name() { /* ... */ } }
Pode-se fazer o seguinte:
List<Widget> widgets = /* ... */; Iterable<Widget> filteredWidgets = IterableUtil.where(widgets, w -> w.name().startsWith("some-prefix"));
Que eu prefiro o seguinte:
List<Widget> widgets = /* ... */; List<Widget> filteredWidgets = new ArrayList<Widget>(); for (Widget w : widgets) { if (w.name().startsWith("some-prefix")) { filteredWidgets.add(w); } }
fonte
Function<T, R>
eConsumer<T>
, você pode encontrar o conjunto completo de interfaces funcionais comuns que o Java fornece aqui .A interface chamável é semelhante a Func.
A interface executável é semelhante à Action.
Em geral, Java usa classes internas anônimas como uma substituição para delegados C #. Por exemplo, é assim que você adiciona código para reagir ao pressionamento de botão na GUI:
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ...//code that reacts to the action... } });
fonte
A elegância dos delegados Func sobrecarregados (além do delegado vs questão de classe anônima) é que eles suportam de 0 a 16 argumentos (
Func<TResult>
,Func<T, TResult>
,Func<T1, T2, TResult>
, etc.)Infelizmente, isso é impossível em Java por causa do apagamento de tipo. As classes não podem diferir apenas por parâmetros de tipo genérico.
Java 8 agora traz um zoológico de nomes como
BiConsumer
forAction<T, T2>
e, porque Java não permite argumentos de tipo primitivoBiIntConsumer
,. O "zoológico", porém, não é muito grande, e não tenho conhecimento de uma biblioteca que o amplie. Havia uma proposta maravilhosa para literais de tipo de função como,(int, int) => void
mas ela não foi adotada.fonte
Func`1
etc. É apenas C # que mapeia aqueles com o mesmo nome.BiConsumer
paraAction<T, T2>
e, porque o Java não permite parâmetros de tipo primitivoBiIntConsumer
,. Havia uma proposta para literais de tipo de função como,(int, int) => void
mas não foi adotada.Para
Func<T>
uso: java.util.function.Supplier http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.htmlfonte
Supplier
seria equivalente aFunc<T>
(em oposição aFunc<T1, T2>
) nãoAction
. UmAction
não aceita argumentos e não retorna nenhum resultado. (Outras versões doAction
aceitam vários números de argumentos e não retornam nenhum resultado.)Func<T>
para Java e erroneamente lembrava comoAction<T>
. OpsAction<>
: 0 entradas, 0 saídas. Na melhor das hipóteses, com.andThen(...)
funcionalidade.Action<>
0 entradas e 0 saídas. Mas, lembre-se, em Java são apenas interfaces. Assim, você pode criar seu próprio para usar.Runnable
paraAction<>
, embora não seja tão bonito para usar como o novo material funcional Java 8.Realmente não há equivalentes para eles. Você pode criar classes internas anônimas em Java, mas tende a haver interfaces específicas em vez de interfaces genéricas como Func e Action.
fonte
Java não tem o conceito de delegados. Para obter uma abordagem alternativa, consulte Um programador Java examina os delegados C # :
fonte
Você pode usar java.util.Function como este
Mas se você for usá-lo com mais de um argumento (como o C # Func faz), você deve definir sua versão de FunctionalInterface da seguinte maneira
@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); }
Então você pode usar com a variável nº de argumentos
fonte
Para versões anteriores ao Java 8
Para retornos de chamada de método em C # que usei assim:
public void MyMethod(string par1, string par2, Action<int> callback, Action<int, string> callback2) { //Async Code callback.invoke(1); callback2.invoke(4, "str"); }
e chamando de:
utils.MyMethod("par1", "par2", (i) => { //cb result }, (i, str) => { //cb2 result });
Eu fiz pequenas classes abstratas em 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
Método Java se parece com:
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"); }
Agora, ao chamá-lo em 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 } });
Isso também funciona passando / definindo seus retornos de chamada para as classes nas quais você deseja chamá-los. O mesmo método pode ser usado para criar interfaces também:
package com.example.app.interfaces; public interface MyInterface<T> { void makeDo(T obj); void makeAnotherDo(); }
fonte