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

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

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

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.


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


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.


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.


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();

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();
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.