【问题标题】:Java's equivalents of Func and ActionJava 的 Func 和 Action 等价物
【发布时间】:2021-07-26 13:18:59
【问题描述】:

FuncAction 的 Java 等价物是什么?

我的意思是,不要自己写这个:

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

【问题讨论】:

标签: java


【解决方案1】:

在 Java 8 中,等价物分别是 java.util.function.Function&lt;T, R&gt;java.util.function.Consumer&lt;T&gt; 接口。同样,java.util.function.Predicate&lt;T&gt; 等价于 System.Predicate&lt;T&gt;。如其他地方所述,这些是接口而不是委托。

除此之外:我目前非常依赖以下实用程序类来执行类似 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&lt;TSource&gt;System.Linq.Enumerable.Select&lt;TSource, TResult&gt; 不同,我在这里介绍的类似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);
  }
}

【讨论】:

  • 我们真的需要对这个答案投赞成票,因为这个问题是“Java 等效操作”的当前排名第一的搜索结果,现在是 2015 年,所以 Java 8 的东西比 Java 以前的要好得多在这一点上几乎模仿了 .net 的东西。
  • 我认为你的意思是 Iterable filteredWidgets = IterableUtil.where(widgets, w -> w.name().startsWith("some-prefix"));
  • 除了Function&lt;T, R&gt;Consumer&lt;T&gt;,还可以找到Java提供的全套常用功能接口here
【解决方案2】:

Callable接口类似于Func。

Runnable 接口类似于Action。

一般来说,Java 使用匿名内部类来替代 C# 委托。 例如,这是您添加代码以响应 GUI 中的按钮按下的方式:

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

【讨论】:

  • Func 与 Callable 的区别在于,最多有 16 个参数的通用重载(Func、Func、Func 等) . OTOH,Callable 没有参数。此外,由于泛型中的类型擦除,不可能实现 C# 的重载。
【解决方案3】:

重载的 Func 委托(除了委托与匿名类问题之外)的优雅之处在于它们支持 0 到 16 个参数(Func&lt;TResult&gt;Func&lt;T, TResult&gt;Func&lt;T1, T2, TResult&gt; 等)

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

Java 8 现在为 Action&lt;T, T2&gt; 引入了诸如 BiConsumer 之类的名称动物园,并且由于 Java 不允许原始类型参数,BiIntConsumer。不过,“动物园”并不是很大,而且我不知道有哪个图书馆可以扩展它。对于像(int, int) =&gt; void 这样的函数类型文字有一个很棒的提议,但没有被采纳。

【讨论】:

  • 有趣的是,在 CLR 级别,只有泛型参数数量不同的类确实有不同的名称。 Func`1 等。只是 C# 将它们映射到相同的名称。
  • @CodesInChaos 啊,很有趣。太糟糕了,Java 也没有这样做。顺便说一句,Java 8 现在为Action&lt;T, T2&gt; 引入了诸如BiConsumer 之类的名称动物园,并且由于Java 不允许原始类型参数BiIntConsumer。曾经有过类似(int, int) =&gt; void 这样的函数类型文字的提议,但没有被采纳。
【解决方案4】:

对于Func&lt;T&gt; 使用:java.util.function.Supplier http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html

【讨论】:

  • Supplier 将等价于Func&lt;T&gt;(相对于Func&lt;T1, T2&gt;)而不是ActionAction 不接受任何参数并且不返回任何结果。 (其他版本的Action 接受不同数量的参数并且不返回结果。)
  • 是的,你是对的,我的错。我遇到了这篇文章,因为我正在寻找 Java 的 Func&lt;T&gt; 并错误地将其记住为 Action&lt;T&gt;。哎呀
  • 无论如何,答案对我很有帮助。 java是否也有类似Action&lt;&gt;的东西:0个输入,0个输出。最好使用.andThen(...) 功能。
  • 我不知道 Java 框架提供的任何东西,例如 Action&lt;&gt;,具有 0 个输入和 0 个输出。但是请记住,在 Java 中,这些只是接口。因此,您可以创建自己的来使用。
  • Runnable 对应于 Action&lt;&gt;,虽然它不如新的 Java 8 函数式的东西那么漂亮。
【解决方案5】:

你可以像这样使用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();

【讨论】:

    【解决方案6】:

    这些确实没有等价物。您可以在 Java 中创建匿名内部类,但往往会有特定的接口,而不是像 Func 和 Action 这样的通用接口。

    【讨论】:

      【解决方案7】:

      Java 没有委托的概念。有关解决方法,请参阅A Java Programmer Looks at C# Delegates

      虽然 C# 有一组功能 类似于Java,它增加了几个 新的和有趣的功能。 委派是对待一个人的能力 方法作为一等对象。一个 C# 委托用于Java开发人员的地方 将使用带有单个接口的接口 方法。在本文中,使用 讨论了 C# 中的委托,以及代码 为 Java 代表提供 可以执行类似操作的对象 功能。下载源代码 在这里。

      【讨论】:

        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

          从Java 8开始,Func和Action可以通过Functional Interface和Lambda Expression来实现。

          Functional Interface 是一种只有一个抽象方法的接口。

          @FunctionalInterface
          interface Drawable {
              void Draw();
          }
          

          @FunctionalInterface 属性是可选的。同时,C# 和 Java 的 Lambda 表达式概念是相同的。

          下面的Java和C#代码是等价的:

          class App
          {
              public static void Main(string[] args)
              {
                  Action action = () => { Console.WriteLine("Printing from App class"); };
                  action();
              }
          }
          
          @FunctionalInterface
          interface Drawable {
              void Draw();
          }
          
          public class App {
              public static void main(String[] args) throws Exception {
                  Drawable drawable = ()->System.out.println("Printing from App class");
                  drawable.Draw();
              }
          }
          

          在 Java 中,Func 和 Action 被替换为函数式接口。

          使用这种接口,Java 不需要特别具有 Func 和 Action 委托类型,因为我们可以创建任何满足 Func 和 Action 的接口(是它的参数和返回类型)。因此,Java 中的代码比 C# 版本要冗长一些。

          (本文总结自https://www.byteinthesky.com/tutorials/func-and-action-equivalent-in-java/

          【讨论】:

            【解决方案10】:

            如果您来自 C# 背景(像我一样)并正在寻找:

            public delegate TResult Func<in T1,in T2,out TResult>(T1 arg1, T2 arg2);
            

            看看:

            public interface BiFunction<T, U, R>
            

            【讨论】:

              【解决方案11】:

              这是我的实现,缺少 Action 多参数类型的通用接口。

              package x.y.delegate;
              
              public class IAction {
                  public interface _0 { void execute(); }
                  public interface _1<T> { void execute(T p); }
                  public interface _2<T1, T2> { void execute(T1 p1, T2 p2); }
                  public interface _3<T1, T2, T3> { void execute(T1 p1, T2 p2, T3 p3); }
                  public interface _4<T1, T2, T3, T4> { void execute(T1 p1, T2 p2, T3 p3, T4 p4); }
                  public interface _5<T1, T2, T3, T4, T5> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5); }
                  public interface _6<T1, T2, T3, T4, T5, T6> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6); }
                  public interface _7<T1, T2, T3, T4, T5, T6, T7> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7); }
                  public interface _8<T1, T2, T3, T4, T5, T6, T7, T8> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8); }
                  public interface _9<T1, T2, T3, T4, T5, T6, T7, T8, T9> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9); }
                  public interface _10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10); }
                  public interface _11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11); }
                  public interface _12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12); }
                  public interface _13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13); }
                  public interface _14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14); }
                  public interface _15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, T15 p15); }
                  public interface _16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> { void execute(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10, T11 p11, T12 p12, T13 p13, T14 p14, T15 p15, T16 p16); }
              }
              
              class DoSomething {
                  public void doSm(IAction._1 ack, IAction._2 ack2) {
              
                  }
              }
              

              或者您可以在此链接中找到我的库,其中包括 Action、Func、Predicate 和 Tuple 的定义: https://github.com/ThinhVu/javaexthttps://jitpack.io/#ThinhVu/javaext/1.0.0

              【讨论】:

                猜你喜欢
                • 2023-03-10
                • 2020-08-04
                • 1970-01-01
                • 2012-06-03
                • 2013-01-15
                • 1970-01-01
                • 2010-11-13
                • 2019-11-03
                • 2011-01-16
                相关资源
                最近更新 更多