Еквіваленти Java Func та Action


Відповіді:


96

У Java 8 еквівалентами є відповідно java.util.function.Function<T, R>і java.util.function.Consumer<T>інтерфейси. Аналогічно, java.util.function.Predicate<T>еквівалентно System.Predicate<T>. Як вже згадувалося в іншому місці, це інтерфейси замість делегатів.

Побіжно: Я наразі сильно спираюся на наступний клас утиліти, щоб робити подібні до 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;
  }
}

В відміну System.Linq.Enumerable.Where<TSource>та System.Linq.Enumerable.Select<TSource, TResult>LINQ, як методи , які я представляю тут не лінуються і повністю пройти колекції джерел до повернення колекції результату абонента. Тим не менш, я вважаю їх корисними для чисто синтаксичних цілей, і я міг би стати лінивими, якщо це необхідно. Дано

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

Можна зробити наступне:

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

Який я віддаю перевагу наступному:

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

1
Нам дійсно потрібно проголосувати за цю відповідь, оскільки це запитання є поточним результатом пошуку № 1 для "еквівалента дії Java", і зараз це 2015 рік, тому речі Java 8 набагато кращі за те, що було в Java раніше, і майже імітує матеріали .net точка.
Роберт К. Барт,

1
Думаю, ви мали на увазі Iterable <Widget> filteredWidgets = IterableUtil.where (віджети, w -> w.name (). StartWith ("some-prefix"));
electricbah

1
На додаток до Function<T, R>та Consumer<T>, ви можете знайти повний набір загальних функціональних інтерфейсів, які Java пропонує тут .
Ямес,

35

Викличний інтерфейс схожий на Func.

Запуск інтерфейсу схожий на Action.

Загалом, Java використовує анонімні внутрішні класи як заміну делегатів C #. Наприклад, ось як ви додаєте код, щоб реагувати на натискання кнопки в графічному інтерфейсі:

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

13
Що відрізняє Func від Callable, так це те, що існують загальні перевантаження до 16 аргументів (Func <TResult>, Func <T, TResult>, Func <T1, T2, TResult> тощо). OTOH, Callable не бере аргументів. Більше того, неможливо реалізувати перевантаження C # через стирання типу в дженериках.
Олександр Дубінський

6

Елегантність перевантажених делегатів Func (крім делегата проти анонімного питання класу) є те , що вони підтримують від 0 до 16 аргументів ( Func<TResult>, Func<T, TResult>, Func<T1, T2, TResult>і т.д.)

На жаль, це неможливо в Java через стирання типу. Класи не можуть відрізнятися лише параметри загального типу.

Java-тепер приносить в зоопарку імен , як BiConsumerдля Action<T, T2>і, оскільки Java не дозволяє аргументи примітивного типу, BiIntConsumer. Однак "зоопарк" не дуже великий, і я не знаю бібліотеки, яка його розширює. Була чудова пропозиція щодо таких типів літералів, як, (int, int) => voidале вона не була прийнята.


3
Цікаво, що на рівні CLR класи, які відрізняються лише кількістю загальних параметрів, мають різні назви. Func`1і т. д. Це просто C #, який відображає їх на те саме ім'я.
CodesInChaos

@CodesInChaos Ах, дуже цікаво. Шкода, що Java теж не зробила цього таким чином. До речі, Java-тепер приносить в зоопарку імен , як BiConsumerдля Action<T, T2>і, оскільки Java не дозволяє параметри примітивного типу, BiIntConsumer. Була пропозиція щодо літералів типу функцій типу, (int, int) => voidале вона не була прийнята.
Олександр Дубінський

5

Для Func<T>використання: java.util.function.Supplier http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html


Supplierбуло б еквівалентно Func<T>(на відміну від Func<T1, T2>) ні Action. A Actionне приймає аргументів і не повертає результату. (Інші версії Actionприймають різну кількість аргументів і не
дають

Так, ти маєш рацію, моя помилка. Я наткнувся на цю публікацію, бо шукав Func<T>Java і помилково запам'ятав її як Action<T>. До жаль
Тім Schruben

Відповідь мені все одно була корисна. Чи є у Java також щось на зразок Action<>: 0 входів, 0 виходів. У кращому випадку з .andThen(...)функціональністю.
Коля Іванков

Мені не відомо нічого, що забезпечується фреймворком Java, подібним Action<>до 0 входів і 0 виходів. Але пам’ятайте, на Java це лише інтерфейси. Отже, ви можете створити свій власний для використання.
Тім Шрубен

Існує Runnableдля Action<>, хоча це не зовсім так добре , щоб використовувати в якості нового Java 8 функціонального матеріалу.
Mark K Cowan

3

Для них насправді немає еквівалентів. Ви можете створювати анонімні внутрішні класи в Java, але, як правило, існують конкретні інтерфейси, а не такі загальні, як Func та Action.


3

Java не має поняття делегатів. Щоб ознайомитись із підходом для вирішення проблем, див. Розділ Програміст Java на Делегати C # :

Хоча C # має набір можливостей, подібних до Java, він додав кілька нових та цікавих функцій. Делегування - це можливість розглядати метод як об’єкт першого класу. Делегат AC # використовується там, де розробники Java використовують інтерфейс з одним методом. У цій статті обговорюється використання делегатів у C #, а також представлений код для об'єкта Java Delegate, який може виконувати подібну функцію. Завантажте вихідний код тут.


3

Ви можете використовувати java.util.Function, як це

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

Але якщо ви хочете використовувати його з кількома аргументами (як це робить C # Func), ви визначили свою версію FunctionalInterface наступним чином

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

Тоді ви можете використовувати зі змінною no аргументів

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

Для зворотних викликів методів у C #, які я використовував так:

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

і називаючи це:

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

Я зробив невеликі абстрактні класи на 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

Метод Java виглядає так:

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

Тепер при виклику на 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
    }
});

Це працює також шляхом передачі / налаштування зворотних викликів класам, в яких ви хочете їх викликати, тим самим методом можна також використовувати для створення інтерфейсів:

package com.example.app.interfaces;
public interface MyInterface<T> {
    void makeDo(T obj);
    void makeAnotherDo();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.