Les équivalents Java de Func et Action

87

Quels sont les équivalents Java de Func et Action ?

Je veux dire, au lieu d'écrire ceci tout seul:

public interface Func<TInput, TResult>
{
    TResult call(TInput target) throws Exception;
}
public interface Action<T>
{
    void call(T target) throws Exception;
}
ripper234
la source

Réponses:

97

Dans Java 8, les équivalents sont respectivement les interfaces java.util.function.Function<T, R>et java.util.function.Consumer<T>. De même, java.util.function.Predicate<T>équivaut à System.Predicate<T>. Comme mentionné ailleurs, ce sont des interfaces au lieu de délégués.

Mis à part: Je m'appuie actuellement fortement sur la classe d'utilitaire suivante pour faire des choses de méthode d'extension de type 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 la différence System.Linq.Enumerable.Where<TSource>et System.Linq.Enumerable.Select<TSource, TResult>la LINQ comme les méthodes que je présente ici ne sont pas paresseux et parcourir entièrement les collections de source avant de retourner les collections de résultats à l'appelant. Pourtant, je les trouve utiles à des fins purement syntaxiques et pourraient être rendues paresseuses si nécessaire. Donné

class Widget {
  public String name() { /* ... */ }
}

On peut faire ce qui suit:

List<Widget> widgets = /* ... */;
Iterable<Widget> filteredWidgets = IterableUtil.where(widgets, w -> w.name().startsWith("some-prefix"));

Ce que je préfère à ce qui suit:

List<Widget> widgets = /* ... */;
List<Widget> filteredWidgets = new ArrayList<Widget>();
for (Widget w : widgets) {
  if (w.name().startsWith("some-prefix")) {
    filteredWidgets.add(w);
  }
}
Richard Cook
la source
1
Nous devons vraiment voter pour cette réponse car cette question est le résultat de recherche n ° 1 actuel pour "l'équivalent Java de l'action" et nous sommes maintenant en 2015, donc le contenu de Java 8 est bien meilleur que ce que Java avait auparavant et imite presque celui de. point.
Robert C. Barth
1
Je pense que vous vouliez dire Iterable <Widget> filteredWidgets = IterableUtil.where (widgets, w -> w.name (). StartsWith ("some-prefix"));
electricbah
1
En plus de Function<T, R>et Consumer<T>, vous pouvez trouver l'ensemble complet des interfaces fonctionnelles communes que Java fournit ici .
Jämes
36

L' interface appelable est similaire à Func.

L' interface exécutable est similaire à Action.

En général, Java utilise des classes internes anonymes en remplacement des délégués C #. Par exemple, voici comment ajouter du code pour réagir à la pression d'un bouton dans l'interface graphique:

button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) { 
          ...//code that reacts to the action... 
      }
});
Grégory Mostizky
la source
13
Ce qui distingue Func de Callable, c'est qu'il existe des surcharges génériques pour jusqu'à 16 arguments (Func <TResult>, Func <T, TResult>, Func <T1, T2, TResult>, etc.). OTOH, Callable ne prend aucun argument. De plus, il est impossible d'implémenter les surcharges de C # à cause de l'effacement de type dans les génériques.
Aleksandr Dubinsky
6

L'élégance des délégués Func surchargées ( en plus du délégué vs question de classe anonyme) est qu'ils prennent en charge de 0 à 16 arguments ( Func<TResult>, Func<T, TResult>, Func<T1, T2, TResult>, etc.)

Malheureusement, cela est impossible en Java en raison de l'effacement de type. Les classes ne peuvent pas différer uniquement par les paramètres de type générique.

Java 8 apporte maintenant dans un zoo des noms comme BiConsumerpour Action<T, T2>et, parce que Java ne permet pas d' arguments de type primitif, BiIntConsumer. Le "zoo", cependant, n'est pas très grand et je ne connais pas de bibliothèque qui l'agrandisse. Il y avait une merveilleuse proposition pour des littéraux de type de fonction comme (int, int) => voidmais elle n'a pas été adoptée.

Aleksandr Dubinsky
la source
3
Fait intéressant, au niveau CLR, les classes qui ne diffèrent que par le nombre de paramètres génériques ont des noms différents. Func`1etc. C'est juste C # qui les mappe au même nom.
CodesInChaos
@CodesInChaos Ahh, très intéressant. Dommage que Java ne l'ait pas fait de cette façon aussi. BTW, Java 8 apporte maintenant dans un zoo des noms comme BiConsumerpour Action<T, T2>et, parce que Java ne permet pas de paramètres de type primitif, BiIntConsumer. Il y avait une proposition pour des littéraux de type de fonction comme (int, int) => voidmais elle n'a pas été adoptée.
Aleksandr Dubinsky
5

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

Tim Schruben
la source
Supplierserait équivalent à Func<T>(par opposition à Func<T1, T2>) non Action. An Actionn'accepte aucun argument et ne renvoie aucun résultat. (Les autres versions de Actionacceptent divers nombres d'arguments et ne renvoient aucun résultat.)
Servy
Oui tu as raison, mon erreur. Je suis tombé sur ce post parce que je cherchais Func<T>Java et que je m'en souvenais à tort comme Action<T>. Oups
Tim Schruben
La réponse m'a de toute façon été utile. Java a-t-il aussi quelque chose comme Action<>: 0 entrées, 0 sorties. Au mieux avec la .andThen(...)fonctionnalité.
Kolya Ivankov
Je ne suis pas au courant de quoi que ce soit fourni par le framework Java qui soit comme Action<>avec 0 entrées et 0 sorties. Mais rappelez-vous, en Java, ce ne sont que des interfaces. Ainsi, vous pouvez créer le vôtre à utiliser.
Tim Schruben
Il y en a Runnablepour Action<>, même si ce n'est pas aussi joli à utiliser que le nouveau matériel fonctionnel Java 8.
Mark K Cowan
3

Il n'y a vraiment pas d'équivalents pour ceux-ci. Vous pouvez créer des classes internes anonymes en Java, mais il existe généralement des interfaces spécifiques plutôt que des interfaces génériques telles que Func et Action.

AgileJon
la source
3

Java n'a pas le concept de délégués. Pour une approche de contournement, veuillez consulter Un programmeur Java regarde les délégués C # :

Bien que C # dispose d'un ensemble de fonctionnalités similaires à Java, il a ajouté plusieurs fonctionnalités nouvelles et intéressantes. La délégation est la capacité de traiter une méthode comme un objet de première classe. Le délégué AC # est utilisé là où les développeurs Java utiliseraient une interface avec une seule méthode. Dans cet article, l'utilisation des délégués en C # est abordée et le code est présenté pour un objet Java Delegate qui peut exécuter une fonction similaire. Téléchargez le code source ici.

Andrew Hare
la source
3

Vous pouvez utiliser java.util.Function comme ceci

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

Mais si vous devez l'utiliser avec plus d'un argument (comme le fait C # Func), vous devez définir votre version de FunctionalInterface comme suit

@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);
}

Ensuite, vous pouvez utiliser avec la variable no d'arguments

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
la source
1

Pour les versions antérieures à Java 8

Pour les rappels de méthode en C # que j'ai utilisés comme ceci:

public void MyMethod(string par1, string par2, Action<int> callback, Action<int, string> callback2)
{
    //Async Code 
        callback.invoke(1);
        callback2.invoke(4, "str");
}

et l'appelant:

utils.MyMethod("par1", "par2", (i) =>
{
    //cb result
}, (i, str) =>
{
    //cb2 result
});

J'ai créé de petites classes abstraites 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

La méthode Java ressemble à:

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");
}

Maintenant, en l'appelant 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
    }
});

Cela fonctionne également en passant / définissant vos rappels aux classes dans lesquelles vous souhaitez les appeler, la même méthode peut également être utilisée pour créer des interfaces:

package com.example.app.interfaces;
public interface MyInterface<T> {
    void makeDo(T obj);
    void makeAnotherDo();
}
Pierre
la source