Equivalentes Java de Func e Action

86

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;
}
ripper234
fonte
Consulte também stackoverflow.com/questions/7296606/…
nawfal

Respostas:

96

No Java 8, os equivalentes são as interfaces java.util.function.Function<T, R>e java.util.function.Consumer<T>respectivamente. Da mesma forma, java.util.function.Predicate<T>é equivalente a System.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>e System.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. Dado

class 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);
  }
}
Richard Cook
fonte
1
Nós realmente precisamos votar nesta resposta, já que esta pergunta é o resultado da pesquisa nº 1 atual para "Java equivalente da ação" e agora é 2015, então as coisas do Java 8 são muito melhores do que o Java tinha antes e quase imita as coisas do .net nisso ponto.
Robert C. Barth
1
Acho que você quis dizer Iterable <Widget> filterWidgets = IterableUtil.where (widgets, w -> w.name (). StartsWith ("some-prefix"));
electricalbah de
1
Além de Function<T, R>e Consumer<T>, você pode encontrar o conjunto completo de interfaces funcionais comuns que o Java fornece aqui .
Jämes de
35

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... 
      }
});
Gregory Mostizky
fonte
13
O que distingue Func de Callable é que existem sobrecargas genéricas para até 16 argumentos (Func <TResult>, Func <T, TResult>, Func <T1, T2, TResult>, etc.). OTOH, Callable não aceita argumentos. Além disso, é impossível implementar sobrecargas do C # devido ao apagamento de tipo nos genéricos.
Aleksandr Dubinsky,
6

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 BiConsumerfor Action<T, T2>e, porque Java não permite argumentos de tipo primitivo BiIntConsumer,. 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) => voidmas ela não foi adotada.

Aleksandr Dubinsky
fonte
3
Curiosamente, no nível CLR, as classes que diferem apenas pelo número de parâmetros genéricos têm nomes diferentes. Func`1etc. É apenas C # que mapeia aqueles com o mesmo nome.
CodesInChaos
@CodesInChaos Ahh, muito interessante. Pena que Java não fez isso também. A propósito, o Java 8 agora traz um zoológico de nomes como BiConsumerpara Action<T, T2>e, porque o Java não permite parâmetros de tipo primitivo BiIntConsumer,. Havia uma proposta para literais de tipo de função como, (int, int) => voidmas não foi adotada.
Aleksandr Dubinsky
5

Para Func<T>uso: java.util.function.Supplier http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html

Tim Schruben
fonte
Supplierseria equivalente a Func<T>(em oposição a Func<T1, T2>) não Action. Um Actionnão aceita argumentos e não retorna nenhum resultado. (Outras versões do Actionaceitam vários números de argumentos e não retornam nenhum resultado.)
Servy
Sim, você está certo, erro meu. Corri para este post, porque eu estava olhando para o Func<T>para Java e erroneamente lembrava como Action<T>. Ops
Tim Schruben
A resposta foi útil para mim de qualquer maneira. O java também tem algo como Action<>: 0 entradas, 0 saídas. Na melhor das hipóteses, com .andThen(...)funcionalidade.
Kolya Ivankov
Não estou ciente de nada fornecido pela estrutura Java que seja como 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.
Tim Schruben de
Não é Runnablepara Action<>, embora não seja tão bonito para usar como o novo material funcional Java 8.
Mark K Cowan
3

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.

AgileJon
fonte
3

Java não tem o conceito de delegados. Para obter uma abordagem alternativa, consulte Um programador Java examina os delegados C # :

Embora C # tenha um conjunto de recursos semelhantes ao Java, ele adicionou vários recursos novos e interessantes. Delegação é a capacidade de tratar um método como um objeto de primeira classe. O delegado AC # é usado onde os desenvolvedores Java usariam uma interface com um único método. Neste artigo, o uso de delegados em C # é discutido e o código é apresentado para um objeto Java Delegate que pode executar uma função semelhante. Baixe o código-fonte aqui.

Andrew Hare
fonte
3

Você pode usar java.util.Function como este

Function<Employee, String> f0 = (e) -> e.toString();

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

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();
user2739602
fonte
1

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();
}
Pierre
fonte