Java的Func和Action等效项


Answers:


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
我们真的需要对此答案投赞成票,因为这个问题是“ Java等价动作”的当前排名第一,而现在是2015年,因此Java 8的内容比Java的要好得多,并且几乎模仿了.net的内容点。
罗伯特·C·巴斯

1
我认为您的意思是Iterable <Widget> filteredWidgets = IterableUtil.where(widgets,w-> w.name()。startsWith(“ some-prefix”));
electricalbah

1
另外的Function<T, R>Consumer<T>,你可以找到全套的常见功能接口Java提供在这里
詹姆斯

35

可调用的接口类似于Func。

可运行的界面类似于Action。

通常,Java使用匿名内部类代替C#委托。例如,这是您添加代码以对GUI中的按钮按下做出反应的方式:

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#的重载。
Aleksandr Dubinsky

6

重载函数功能的代表(除委托VS匿名类问题)的优雅是,他们从0到16个参数支持(Func<TResult>Func<T, TResult>Func<T1, T2, TResult>等)

不幸的是,由于类型擦除,这在Java中是不可能的。类不能仅因泛型类型参数而有所不同。

Java 8现在引入了诸如BiConsumerforAction<T, T2>和as之类的名称,因为Java不允许使用基本类型参​​数BiIntConsumer。但是,“ zoo”不是很大,而且我还不知道可以对其进行扩展的库。对于像这样的函数类型文字有一个很棒的建议,(int, int) => void但是没有被采纳。


3
有趣的是,在CLR级别上,仅泛型参数数量不同的类确实具有不同的名称。Func`1等等。只是C#将它们映射到相同的名称。
CodesInChaos

@CodesInChaos啊,非常有趣。太糟糕的Java也没有这样做。顺便说一句,由于Java不允许基本类型参​​数,因此Java 8现在引入了诸如BiConsumerforAction<T, T2>和as之类的名称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>)not Action。an不Action接受任何参数,也不返回结果。(其他版本的Actionaccept接受各种数量的参数,并且不返回结果。)
Servy

是的,你是对的,我的错。我之所以遇到这篇文章是因为我正在寻找Func<T>Java的,但错误地将其记为Action<T>。糟糕
蒂姆·施鲁本

无论如何,答案对我很有帮助。java是否也有类似的东西Action<>:0输入,0输出。.andThen(...)功能充其量。
Kolya Ivankov

我不知道Java框架提供的任何东西,例如Action<>0输入和0输出。但是请记住,在Java中,这些只是接口。因此,您可以创建自己的使用。
蒂姆·施鲁本

Runnablefor Action<>,尽管它不如新的Java 8功能性东西漂亮。
Mark K Cowan '18

3

确实没有这些替代品。您可以在Java中创建匿名内部类,但是倾向于使用特定的接口,而不是像Func和Action这样的通用接口。


3

Java没有委托的概念。有关解决方法,请参见Java程序员看C#委托

尽管C#具有类似于Java的一组功能,但它增加了一些有趣的新功能。委派是将方法视为一流对象的能力。AC#委托用于Java开发人员将通过单一方法使用接口的情况。在本文中,将讨论C#中委托的使用,并为可执行类似功能的Java委托对象提供代码。在此处下载源代码。


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

然后,您可以使用不带参数的变量

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();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.