Java'nın Func ve Action eşdeğerleri


Yanıtlar:


100

Java 8'de, eşdeğerler sırasıyla java.util.function.Function<T, R>ve java.util.function.Consumer<T>arayüzleridir. Benzer şekilde java.util.function.Predicate<T>eşdeğerdir System.Predicate<T>. Başka bir yerde belirtildiği gibi, bunlar delege yerine arayüzlerdir.

Bir yana ilgili: Şu anda LINQ benzeri uzantı yöntemi şeyler yapmak için aşağıdaki yardımcı program sınıfına büyük ölçüde eğiliyorum:

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

Tersine System.Linq.Enumerable.Where<TSource>ve System.Linq.Enumerable.Select<TSource, TResult>burada sunduğum LINQ benzeri yöntemler tembel değildir ve sonuç koleksiyonlarını çağırana döndürmeden önce kaynak koleksiyonlarını tam olarak çaprazlar. Yine de, onları tamamen sözdizimsel amaçlar için yararlı buluyorum ve gerekirse tembel hale getirilebilir. Verilen

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

Aşağıdakiler yapılabilir:

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

Aşağıdakileri tercih ederim:

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

1
Bu soru "Java eşdeğeri eylem" için mevcut 1 numaralı arama sonucu olduğundan ve şu anda 2015 olduğundan, Java 8 içeriği Java'nın daha önce sahip olduğundan çok daha iyi ve .net'in bu konudaki malzemelerini neredeyse taklit ettiği için bu cevabı gerçekten yükseltmemiz gerekiyor nokta.
Robert C. Barth

1
Sanırım Yinelenebilir <Widget> filteredWidgets = IterableUtil.where (widgets, w -> w.name (). StartsWith ("bir-önek"));
electricbah

1
İlave olarak Function<T, R>ve Consumer<T>Java sağladığını, ortak fonksiyonel arayüzler tam set bulabilirsiniz burada .
Jämes

36

Çağrılabilir arayüz Func'a benzer.

Çalıştırılabilir arayüz, Eylem'e benzer.

Genelde Java, C # temsilcilerinin yerine anonim iç sınıfları kullanır. Örneğin, GUI'de düğmeye basmaya tepki verecek kodu şu şekilde eklersiniz:

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

13
Func'u Callable'dan ayıran şey, 16 argümana kadar jenerik aşırı yüklerin olmasıdır (Func <TResult>, Func <T, TResult>, Func <T1, T2, TResult>, vb.). OTOH, Callable hiçbir argüman almaz. Ayrıca, jeneriklerdeki tür silme nedeniyle C # 'ın aşırı yüklemelerini uygulamak imkansızdır.
Aleksandr Dubinsky

6

(Anonim sınıf sorunu vs temsilci yanı sıra) aşırı Func delegelerin zarafet onlar 0 ila 16 tartışmalardan destekleyen olmasıdır ( Func<TResult>, Func<T, TResult>, Func<T1, T2, TResult>vs.)

Ne yazık ki, tür silme nedeniyle bu Java'da imkansızdır. Sınıflar, yalnızca genel tür parametrelerine göre farklılık gösteremez.

Java 8 şimdi BiConsumerfor Action<T, T2>and gibi bir hayvanat bahçesi getiriyor , çünkü Java ilkel tip argümanlarına izin vermiyor BiIntConsumer. Yine de "hayvanat bahçesi" çok büyük değil ve onu genişleten bir kütüphanenin farkında değilim. İşlev türü değişmezleri gibi harika bir öneri (int, int) => voidvardı ama kabul edilmedi.


3
İlginç bir şekilde, yalnızca genel parametrelerin sayısı ile farklılık gösteren CLR seviyesinde sınıfların farklı isimleri vardır. Func`1vb. Bunları aynı isimle eşleyen C #.
CodesInChaos

@CodesInChaos Ahh, çok ilginç. Java'nın da bu şekilde yapmaması çok kötü. Btw, Java 8 şimdi BiConsumerfor Action<T, T2>and gibi bir hayvanat bahçesi getiriyor , çünkü Java ilkel tür parametrelerine izin vermiyor BiIntConsumer,. İşlev türü değişmezleri için bir öneri (int, int) => voidvardı ama kabul edilmedi.
Aleksandr Dubinsky

5

İçin Func<T>kullanım: java.util.function.Supplier http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html


Suppliernot'a eşdeğer olacaktır Func<T>(aksine Func<T1, T2>) Action. An Actionhiçbir argüman kabul etmez ve sonuç döndürmez. (Diğer sürümler Actionçeşitli sayıda bağımsız değişken kabul eder ve sonuç döndürmez.)
Servy

Evet haklısın benim hatam. Bu gönderiye rastladım çünkü Func<T>Java'yı arıyordum ve yanlışlıkla olarak hatırladım Action<T>. Oops
Tim Schruben

Cevap yine de bana yardımcı oldu. Java da şöyle bir şeye sahip mi Action<>: 0 girdi, 0 çıktı. En iyi ihtimalle .andThen(...)işlevsellikle.
Kolya Ivankov

Java çerçevesi tarafından sağlanan Action<>, 0 girdi ve 0 çıktı gibi bir şeyden haberdar değilim . Ama unutmayın, Java'da bunlar sadece arayüzlerdir. Böylece, kendi kullanımınızı yaratabilirsiniz.
Tim Schruben

Orada Runnableiçin Action<>yeni bir Java 8 işlevsel malzeme olarak kullanmak oldukça kadar güzel olmasa da.
Mark K Cowan

3

Gerçekten bunların eşdeğeri yok. Java'da anonim iç sınıflar oluşturabilirsiniz, ancak Func ve Action gibi jenerik arayüzler yerine belirli arayüzler olma eğilimindedir.


3

Java, temsilci kavramına sahip değildir. Geçici bir çözüm yaklaşımı için lütfen bkz. Bir Java Programcısı C # Temsilcilerine Bakıyor :

C #, Java'ya benzer bir takım yeteneklere sahipken, birçok yeni ve ilginç özellik ekledi. Yetki, bir yöntemi birinci sınıf bir nesne olarak ele alma yeteneğidir. AC # delegate, Java geliştiricilerinin tek bir yöntemle bir arabirim kullanacağı durumlarda kullanılır. Bu makalede, C # 'da temsilcilerin kullanımı tartışılmış ve benzer bir işlevi gerçekleştirebilen bir Java Delegate nesnesi için kod sunulmuştur. Kaynak kodunu buradan indirin.


3

Java.util.Function'ı bu şekilde kullanabilirsiniz

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

Ancak, onu birden fazla bağımsız değişkenle kullanacaksanız (C # Func'un yaptığı gibi), o zaman FunctionalInterface sürümünüzü aşağıdaki gibi tanımlamış olursunuz.

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

O zaman değişken no argüman ile kullanabilirsiniz

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

Java 8'den daha eski sürümler için

Şu şekilde kullandığım C # 'da yöntem geri çağırmaları için:

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

ve ona sesleniyor:

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

Java'da küçük soyut sınıflar yaptım

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

Java Yöntemi şuna benzer:

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

Şimdi onu Java'da ararken:

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

Bu, geri aramalarınızı onları çağırmak istediğiniz sınıflara ileterek / ayarlayarak da çalışır, aynı yöntem Arabirimler oluşturmak için de kullanılabilir:

package com.example.app.interfaces;
public interface MyInterface<T> {
    void makeDo(T obj);
    void makeAnotherDo();
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.