Gli equivalenti di Java di Func e Action


90

Quali sono gli equivalenti Java di Func e Action ?

Voglio dire, invece di scrivere questo da solo:

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

Risposte:


100

In Java 8, gli equivalenti sono rispettivamente le interfacce java.util.function.Function<T, R>e java.util.function.Consumer<T>. Allo stesso modo, java.util.function.Predicate<T>è equivalente a System.Predicate<T>. Come accennato altrove, si tratta di interfacce anziché di delegati.

Correlati a parte: attualmente mi sto appoggiando pesantemente alla seguente classe di utilità per fare cose sul metodo di estensione simile 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 differenza System.Linq.Enumerable.Where<TSource>e System.Linq.Enumerable.Select<TSource, TResult>il LINQ come i metodi che presento qui non sono pigro e percorro pienamente le collezioni di origine prima di tornare alle collezioni di risultato al chiamante. Tuttavia, li trovo utili per scopi puramente sintattici e potrebbero essere resi pigri se necessario. Dato

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

Si può fare quanto segue:

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

Quale preferisco al seguente:

List<Widget> widgets = /* ... */;
List<Widget> filteredWidgets = new ArrayList<Widget>();
for (Widget w : widgets) {
  if (w.name().startsWith("some-prefix")) {
    filteredWidgets.add(w);
  }
}

1
Abbiamo davvero bisogno di votare questa risposta in quanto questa domanda è l'attuale risultato di ricerca n. 1 per "Java equivalente dell'azione" ed è ora il 2015, quindi il materiale di Java 8 è molto migliore di quello che aveva Java e imita quasi quello di .net in questo punto.
Robert C. Barth

1
Penso che intendevi Iterable <Widget> filteredWidgets = IterableUtil.where (widgets, w -> w.name (). StartsWith ("some-prefix"));
electricbah

1
Oltre a Function<T, R>e Consumer<T>, puoi trovare il set completo di interfacce funzionali comuni fornite da Java qui .
Jämes

36

L' interfaccia richiamabile è simile a Func.

L' interfaccia eseguibile è simile ad Action.

In generale, Java utilizza classi interne anonime in sostituzione dei delegati C #. Ad esempio, questo è il modo in cui aggiungi il codice per reagire alla pressione del pulsante nella GUI:

button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) { 
          ...//code that reacts to the action... 
      }
});

13
Ciò che distingue Func da Callable è che esistono overload generici per un massimo di 16 argomenti (Func <TResult>, Func <T, TResult>, Func <T1, T2, TResult>, ecc.). OTOH, Callable non accetta argomenti. Inoltre, è impossibile implementare gli overload di C # a causa della cancellazione del tipo nei generics.
Aleksandr Dubinsky

6

L'eleganza dei delegati Func overload (oltre il delegato vs questione di classe anonima) è che essi supportano da 0 a 16 argomenti ( Func<TResult>, Func<T, TResult>, Func<T1, T2, TResult>, etc.)

Sfortunatamente, questo è impossibile in Java a causa della cancellazione del tipo. Le classi non possono differire solo per parametri di tipo generico.

Java 8 ora porta in uno zoo di nomi come BiConsumerper Action<T, T2>e, perché Java non permette argomenti di tipo primitivo, BiIntConsumer. Lo "zoo", però, non è molto grande, e non sono a conoscenza di una biblioteca che lo amplia. C'era una meravigliosa proposta per i letterali di tipo funzione come (int, int) => voidma non è stata adottata.


3
È interessante notare che a livello di CLR le classi che differiscono solo per il numero di parametri generici hanno nomi diversi. Func`1ecc. È solo C # che mappa quelli con lo stesso nome.
CodesInChaos

@CodesInChaos Ahh, molto interessante. Peccato che anche Java non l'abbia fatto in questo modo. Btw, Java 8 ora porta in uno zoo di nomi come BiConsumerper Action<T, T2>e, perché Java non consente parametri di tipo primitivo, BiIntConsumer. C'era una proposta per i letterali del tipo di funzione come (int, int) => voidma non è stata adottata.
Aleksandr Dubinsky

5

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


Suppliersarebbe equivalente a Func<T>(al contrario di Func<T1, T2>) no Action. An Actionnon accetta argomenti e non restituisce alcun risultato. (Altre versioni di Actionaccettano vari numeri di argomenti e non restituiscono alcun risultato.)
Servy

Sì, hai ragione, errore mio. Mi sono imbattuto in questo post perché stavo cercando Func<T>Java e l'ho ricordato erroneamente come Action<T>. Oops
Tim Schruben

La risposta è stata comunque utile per me. Java ha anche qualcosa come Action<>: 0 input, 0 output. Al massimo con la .andThen(...)funzionalità.
Kolya Ivankov

Non sono a conoscenza di nulla fornito dal framework Java che è come Action<>con 0 input e 0 output. Ma ricorda, in Java queste sono solo interfacce. Quindi, puoi crearne uno tuo da usare.
Tim Schruben

C'è Runnableper Action<>, anche se non è così bello da usare come il nuovo materiale funzionale di Java 8.
Mark K Cowan

3

Non ci sono davvero equivalenti per quelli. È possibile creare classi interne anonime in Java, ma tendono ad esserci interfacce specifiche piuttosto che quelle generiche come Func e Action.


3

Java non ha il concetto di delegati. Per un approccio alternativo, vedere un programmatore Java esamina i delegati C # :

Sebbene C # abbia una serie di funzionalità simili a Java, ha aggiunto diverse nuove e interessanti funzionalità. La delega è la capacità di trattare un metodo come un oggetto di prima classe. Il delegato AC # viene utilizzato quando gli sviluppatori Java utilizzano un'interfaccia con un unico metodo. In questo articolo viene discusso l'uso dei delegati in C # e viene presentato il codice per un oggetto Java Delegate che può eseguire una funzione simile. Scarica il codice sorgente qui.


3

Puoi usare java.util.Function in questo modo

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

Ma se devi usarlo con più di un argomento (come fa C # Func), allora devi definire la tua versione di FunctionalInterface come segue

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

Quindi puoi usare con la variabile no di argomenti

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

Per versioni precedenti rispetto a Java 8

Per i callback dei metodi in C # che ho usato in questo modo:

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

e chiamandolo:

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

Ho creato piccole classi astratte in 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

Il metodo Java ha il seguente aspetto:

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

Ora, quando lo chiami in 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
    }
});

Funziona anche passando / impostando i tuoi callback alle classi in cui vuoi chiamarli, lo stesso metodo può essere utilizzato anche per creare Interfacce:

package com.example.app.interfaces;
public interface MyInterface<T> {
    void makeDo(T obj);
    void makeAnotherDo();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.