Padanan Java untuk Func and Action


Jawaban:


100

Di Java 8, padanannya masing- masing adalah antarmuka java.util.function.Function<T, R>dan java.util.function.Consumer<T>. Demikian pula, java.util.function.Predicate<T>setara dengan System.Predicate<T>. Seperti disebutkan di tempat lain, ini adalah antarmuka, bukan delegasi.

Selain terkait: Saat ini saya sangat bergantung pada kelas utilitas berikut untuk melakukan hal-hal metode ekstensi seperti 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;
  }
}

Tidak seperti System.Linq.Enumerable.Where<TSource>dan System.Linq.Enumerable.Select<TSource, TResult>metode mirip LINQ yang saya sajikan di sini tidak malas dan sepenuhnya melintasi koleksi sumber sebelum mengembalikan koleksi hasil ke pemanggil. Namun, saya menganggapnya berguna untuk tujuan sintaksis murni dan dapat dibuat malas jika perlu. Diberikan

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

Seseorang dapat melakukan hal berikut:

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

Yang saya lebih suka dari yang berikut:

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

1
Kami benar-benar perlu memberi suara pada jawaban ini karena pertanyaan ini adalah hasil pencarian # 1 saat ini untuk "Java equivalent of action" dan sekarang sudah 2015 sehingga hal-hal Java 8 jauh lebih baik daripada yang dimiliki Java sebelumnya dan hampir meniru hal-hal .net saat ini titik.
Robert C. Barth

1
Saya pikir yang Anda maksud adalah Iterable <Widget> filteredWidgets = IterableUtil.where (widgets, w -> w.name (). BeginWith ("some-prefix"));
electricalbah

1
Selain Function<T, R>dan Consumer<T>, Anda dapat menemukan set lengkap antarmuka fungsional umum yang disediakan Java di sini .
Jämes

36

Antarmuka yang dapat dipanggil mirip dengan Func.

Antarmuka yang dapat dijalankan mirip dengan Action.

Secara umum, Java menggunakan kelas dalam anonim sebagai pengganti delegasi C #. Misalnya, ini adalah bagaimana Anda menambahkan kode untuk bereaksi terhadap penekanan tombol di GUI:

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

13
Yang membedakan Func dari Callable, adalah bahwa terdapat kelebihan beban umum hingga 16 argumen (Func <TResult>, Func <T, TResult>, Func <T1, T2, TResult>, dll.). OTOH, Callable tidak membutuhkan argumen. Selain itu, tidak mungkin untuk mengimplementasikan overload C # karena penghapusan tipe pada generik.
Aleksandr Dubinsky

6

Keanggunan delegasi Func yang kelebihan beban (selain delegasi vs masalah kelas anonim) adalah bahwa mereka mendukung 0-16 argumen ( Func<TResult>, Func<T, TResult>, Func<T1, T2, TResult>, dll)

Sayangnya, ini tidak mungkin di Jawa karena penghapusan tipe. Kelas tidak dapat dibedakan dengan parameter tipe generik saja.

Java 8 sekarang menghadirkan banyak nama seperti BiConsumerfor Action<T, T2>dan, karena Java tidak mengizinkan argumen tipe primitif BiIntConsumer,. "Kebun binatang", bagaimanapun, tidak terlalu besar, dan saya tidak mengetahui perpustakaan yang mengembangkannya. Ada proposal bagus untuk literal tipe fungsi seperti (int, int) => voidtetapi tidak diadopsi.


3
Menariknya, pada kelas level CLR yang hanya berbeda dengan jumlah parameter generik memang memiliki nama yang berbeda. Func`1dll. Hanya C # yang memetakan mereka ke nama yang sama.
CodesInChaos

@CodesInChaos Ahh, sangat menarik. Sayang sekali Java tidak melakukannya dengan cara ini juga. Btw, Java 8 sekarang menghadirkan kebun binatang dengan nama-nama seperti BiConsumerfor Action<T, T2>dan, karena Java tidak mengizinkan parameter tipe primitif BiIntConsumer,. Ada usulan untuk literal tipe fungsi seperti (int, int) => voiditu tetapi tidak diadopsi.
Aleksandr Dubinsky

5

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


Supplierakan sama dengan Func<T>(sebagai lawan Func<T1, T2>) tidak Action. An Actiontidak menerima argumen dan tidak mengembalikan hasil. (Versi lain dari Actionmenerima berbagai jumlah argumen dan tidak mengembalikan hasil.)
Pelayanan

Ya, Anda benar, kesalahan saya. Saya menemukan posting ini karena saya mencari Func<T>Java dan secara keliru mengingatnya sebagai Action<T>. Ups
Tim Schruben

Jawabannya sangat membantu saya. Apakah java juga memiliki sesuatu seperti Action<>: 0 input, 0 output. Paling baik dengan .andThen(...)fungsionalitas.
Kolya Ivankov

Saya tidak mengetahui apa pun yang disediakan oleh kerangka kerja Java yang seperti Action<>dengan 0 input dan 0 output. Tapi ingat, di Java ini hanya antarmuka. Jadi, Anda bisa membuatnya sendiri untuk digunakan.
Tim Schruben

Ada Runnableuntuk Action<>, meskipun tidak cukup sebagai cantik untuk digunakan sebagai baru Java 8 hal fungsional.
Mark K Cowan

3

Benar-benar tidak ada padanan untuk itu. Anda dapat membuat kelas dalam anonim di Java, tetapi cenderung ada antarmuka khusus daripada antarmuka umum seperti Func dan Action.


3

Java tidak memiliki konsep delegasi. Untuk pendekatan solusi, silakan lihat Pemrogram Java Melihat Delegasi C # :

Meskipun C # memiliki serangkaian kemampuan yang mirip dengan Java, C # telah menambahkan beberapa fitur baru dan menarik. Delegasi adalah kemampuan untuk memperlakukan metode sebagai objek kelas satu. AC # delegate digunakan di mana pengembang Java akan menggunakan antarmuka dengan metode tunggal. Pada artikel ini, penggunaan delegasi di C # dibahas, dan kode disajikan untuk objek Delegasi Java yang dapat melakukan fungsi serupa. Unduh kode sumbernya di sini.


3

Anda dapat menggunakan java.util.Fungsi seperti ini

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

Tetapi jika Anda akan menggunakannya dengan lebih dari satu argumen (seperti yang dilakukan C # Func), maka Anda telah menentukan versi FunctionalInterface sebagai berikut

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

Kemudian Anda dapat menggunakan dengan variabel tidak ada argumen

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

Untuk versi yang lebih lama dari Java 8

Untuk metode callback di C # yang saya gunakan seperti ini:

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

dan menyebutnya:

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

Saya telah membuat kelas abstrak kecil di Jawa

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

Metode Java terlihat seperti:

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

Sekarang saat memanggilnya di 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
    }
});

Ini juga berfungsi dengan meneruskan / menyetel callback Anda ke kelas tempat Anda ingin memanggilnya, metode yang sama juga dapat digunakan untuk membuat Antarmuka:

package com.example.app.interfaces;
public interface MyInterface<T> {
    void makeDo(T obj);
    void makeAnotherDo();
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.