Подтвердить что ты не робот

Java-эквиваленты Func и Action

Что такое эквиваленты Java Func и Действие?

Я имею в виду, вместо того, чтобы писать это самостоятельно:

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

Ответ 1

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

Ответ 2

Callable интерфейс похож на Func.

Runnable интерфейс похож на действие.

В общем, Java использует анонимные внутренние классы в качестве замены делегатов С#. Например, так вы добавляете код для реагирования на нажатие кнопки в GUI:

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

Ответ 3

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

К сожалению, это невозможно в Java из-за стирания типа. Классы не могут отличаться только параметрами типового типа.

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

Ответ 4

Для них действительно нет эквивалентов. Вы можете создавать анонимные внутренние классы в Java, но обычно существуют определенные интерфейсы, а не такие общие, как Func и Action.

Ответ 5

Java не имеет понятия делегатов. Обходной подход можно найти в Программист Java Посмотрит на делегатов С#:

В то время как С# имеет набор возможностей подобно Java, он добавил несколько новые и интересные функции. Делегирование - это способность рассматривать метод как объект первого класса. С# делегат используется там, где разработчики Java будет использовать интерфейс с одним метод. В этой статье использование делегаты в С#, и код представлен для делегата Java объект, который может выполнять аналогичные функция. Загрузите исходный код здесь.

Ответ 7

Вы можете использовать java.util.Function, как это

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

Но если вы хотите использовать его с более чем одним аргументом (как это делает С# 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();

Ответ 8

Для более старых версий, чем Java 8

Для обратных вызовов методов в С#, которые я использовал следующим образом:

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