在Java 8的java.util.function软件包中,我们具有:



功能:接受一个参数,产生一个结果。

消费者:接受一个参数,不产生任何结果。

供应商:不带参数,不产生一个结果。

...:其他处理基元,2个参数等的情况...

,但我需要处理“不带任何参数,不产生任何结果”的情况。

java.util.functionnal中没有与此相关的内容。

所以,这个问题是:

“不带任何参数却不返回任何值的函数”的名字是什么?

在Java 8中,其定义为:

@FunctionalInterface
public interface InsertANameHere {
    void execute();
}


执行器已经存在,并且具有另一个目的:“执行提交的可运行任务的对象”。签名不匹配(execute(Runnable):void),甚至都不是功能接口。

Runnable存在,但它与线程上下文紧密关联:


程序包是java.lang,而不是java.util.function
javadoc指出:“ Runnable接口应该由实例打算由线程执行的任何类实现。”
名称“ Runnable”表示正在运行线程内的代码。


评论

“但是“什么都不做,什么也不做。”没有任何意义。”-Runnable?

我认为针对Runnable的javadoc在这一点上已经过时,因为Runnable也被Thread(例如Executor)以外的其他类使用。

@superbob并不意味着Runnables只能由Threads.run()来实现。实际上,它们非常普遍地用于问题中所述的目的

@superbob那是最初的目的,但是从Java 8开始,它被“改造”为功能接口。所以这就是为什么在java.util.function包中什么都找不到的原因。
Semi-Snark:ImpureFuntion,因为它肯定仅依赖于副作用,否则为空。 (en.wikipedia.org/wiki/Pure_function#Impure_functions)更严格:命令式(执行某些操作),至少应与void execute()的语义相匹配;

#1 楼

Java选择这样做的方式是为每个Arity单独命名,这完全不值得模仿。但是,如果出于一致性考虑必须这样做,或者正在编写非常通用的库代码,则Konrad的建议是好的。我可能会把Procedure丢进去。

使用伪函数范式并不意味着正常的命名原则应该消失。接口应该几乎总是以其作用命名,而不是以某种通用的语法思想命名。如果将函数放置在撤消堆栈中,则应将其命名为UndoFunction。如果从GUI事件中调用它们,则应将其命名为GUIEventHandler

评论


程序也很好。对于上下文,我正在开发一个通用库,该库需要处理这种“结构”。

–superbob
15年3月20日在13:16

我从Pascal时代开始喜欢Procedure。一个过程有副作用,一个功能没有副作用。由于您不返回任何值,因此它唯一可以做的就是产生副作用。

– Spencer Rathbun
15年3月20日在15:41

确实,真正的函数式编程通常不鼓励匈牙利风格的命名。这更多是oo范式的心态而非功能。

– slebetman
15年3月21日在1:03

如果将函数放置在撤消堆栈中,则应将其命名为UndoFunction。不过,给函数命名和给它不同的类型之间是有区别的。在函数式风格中,您不会创建UndoFuncton类型,因为现在您无法将其传递给翻转,咖喱,撰写,过滤,映射等。在我看来,这就是Java决定给具有不同类型的函数提供不同名称的真正原因。是愚蠢的。当然,如果您要使用副作用,可以随便叫它;您已经把合成扔到了窗外,并且可以说您也不使用任何函数。

–Doval
2015年3月21日在16:57



诸如Consumer 之类的名称比UsernameCallback更好,但仍不如指定诸如String => Unit之类的简单签名那样好。

–卡尔·比勒费尔德(Karl Bielefeldt)
18-10-3在22:23

#2 楼

在Java世界中,它称为Runnable。在C#世界中,它称为Action

但是,有一个更好的名称正好适合更大范围的事物。

稍​​后,当您决定除了无参数的void功能接口之外,您还需要具有类似的功能接口,这些功能接口可以接受一个,两个或多个参数,或者返回一个值,这是事物的大视角。发生这种情况时,您将希望所有这些实体的名称都是同构的并且彼此对应。

因此,在Java中,我有自己的一组函数接口,称为Procedure,其定义如下:

public interface Procedure
{
    void invoke();
}

public interface Procedure1<T1>
{
    void invoke( T1 argument1 );
}


.. 。(您可以看到图片。)而且我还有一组类似的接口Function s,它们以类似的方式定义,第一个通用参数是返回类型:

public interface Function<R>
{
    R invoke();
}

public interface Function1<R,T1>
{
    R invoke( T1 argument1 );
}


所以,我的意思是Procedure是一个很好的名字,因为它很适合大范围的观察。如果您以后决定使用可以接受参数或返回值的方法来使用相似的功能接口,则会遇到这种情况。

注意:我基本上同意卡尔·比勒费尔德(Karl Bielefeldt)的主张,即“正常命名原则应[而不是走出窗口”,并说“几乎应该总是以接口的名称来命名接口,而不是以某种通用的句法概念命名。”但是请注意,即使他也允许“几乎总是”。有时需要(基本上是匿名的)过程和函数,这就是OP的要求,这就是我要回答的问题。

修订2017-11-10:

您可能会问,为什么用Function1<R,T1>而不是Function1<T1,R>?可以采用任何一种方式,但是我偏爱左侧的返回值,因为我喜欢遵循“转换为”(目的地为源)命名约定,而不是“转换为”(源为-destination)约定。 (从某种意义上说,这比公约更像是一场意外,实际上在某种意义上说,没有人会给它任何想法,因为如果他们给了它任何想法,他们就会达成``转换为''公约。 )

我在Joel Spolksy中读到了有关“使错误的代码看起来错误”的文章,这是一篇很长的文章,我建议全文阅读,但是如果您想直接阅读本文, ,搜索“ TypeFromType”,但为了给您提供TL; DR,我们的想法是myint = intFromStr( mystr )myint = strToInt( mystr )更好,因为在第一种情况下,类型的名称接近于关联的值,因此您可以轻松地看到“ int”与“ int”匹配,而“ str”与“ str”匹配。

因此,通过扩展,我倾向于按事物在代码中的显示顺序进行排序。

评论


这个解决方案确实非常好,它似乎比Java自己的Supplier,Consumer,BiFunction ...更具防弹能力,因为它将所有内容归结为两个概念。它让我想起了@Karl Bielefeldt的回答:“ Java选择以这种方式为每个愚蠢的人使用一个单独的名称来做到这一点”。唯一的“缺点”是它不处理原始类型及其组合(有趣的东西,如DoubleToLongFunction,ToLongBiFunction等)。但是原始是另一个问题...

–superbob
15年3月20日在15:20

是。基本上,一旦开始用基元替换泛型,这意味着您真的在乎性能,因此如果您偏离此处介绍的约定并使用高度自定义的名称来进行高度自定义的性能改进,则可以。

–迈克·纳基斯(Mike Nakis)
2015年3月20日15:32



如果我可以接受第二个答案,那么我将根据程序N,功能N的建议选择您的答案。我仍然支持它。

–superbob
2015年3月21日在12:19



为什么不是Function1

– ErikE
17年11月20日在1:06

@ErikE是一个很好的问题,我修改了帖子以回答。

–迈克·纳基斯(Mike Nakis)
17年11月20日在11:10

#3 楼

为什么不Command?假设它不接收任何数据并且不返回任何数据,但是假设调用它会产生某种效果(否则实际上是毫无意义的),我想那大概是它唯一可以做的事情-触发一个动作,使某件事发生。 />说到这,.NET中还有一个通用的Action委托。与Java的Consumer不同,它可以接受0到16个参数。换句话说,最简单的版本不需要任何内容​​-请参见MSDN。

由于名称并不意味着可以“使用”任何东西,因此它似乎也是一个不错的名称选择。

评论


命令好。可以将其与Command模式混淆,但这可能是解决方案。

–superbob
2015年3月20日在13:01



我更喜欢Action,而不是Command。命令听起来更像是被接收和评估的东西,而执行操作则有其副作用。

–贝尔吉
2015年3月20日在13:47



嗯...怎么可能不是命令模式?您已经完全构建了Command实体!它甚至具有传统名称的execute()方法。 0_o'

–hijarian
15年3月20日在14:47

不喜欢Action的建议,因为这是一个常见的(也是很好的)Swing接口。命令是合理的。

–user949300
15年3月20日在16:30

@ user949300,但这取决于上下文-Java是一个广阔的世界,您是一名Android开发人员(现在),并且没有与J2EE相关的特质;)我当然同意,所选的命名约定不应冲突与您的框架使用的那个。

– Konrad Morawski
2015年3月20日在20:20