【问题标题】:What is the difference between a Predicate and a Function Interface in Java8?Java 8 中的谓词和函数接口有什么区别?
【发布时间】:2018-07-20 15:00:45
【问题描述】:

我知道这可能是关于 SO 的一个非常基本的问题,但我想知道 Java8 中的 PredicateFunction 接口有什么区别?

Predicate<String> predicateTest  = (s)-> s.length() > 5;       
System.out.println(predicateTest.test("Predicate"));

Function<String, Boolean> functionTest = str -> str.length()> 5;      
System.out.println(functionTest.apply("Function"));

在我的示例中,两者都返回true。唯一的问题是调用方式不同?

【问题讨论】:

  • 一个Predicate 只是一个返回BooleanFunction。换句话说,Predicate&lt;T&gt;Function&lt;T, Boolean&gt;。但是Predicate返回一个boolean所以没有继承关系。
  • @BoristheSpider nitpick,它是 boolean 而不是 Boolean
  • @Eugene 只是整理一下
  • 嗯,这是根本的区别。 Predicate 函数的计算结果可能为 truefalse,仅此而已。 Function&lt;…,Boolean&gt; 可能返回 Boolean.TRUEBoolean.FALSEanother Boolean instance 代表 truefalsenull

标签: java function java-8 predicate


【解决方案1】:

Predicate&lt;T&gt;Function&lt;T, R&gt; 之间的区别

首先,Predicate&lt;T&gt;严格是一个布尔值函数:

         _ _ _ _ _ _ _ 
        |             |
  T --> |  predicate  | --> boolean
        |_ _ _ _ _ _ _|   

Function&lt;T, R&gt; 不一定是这样:

         _ _ _ _ _ _ _ 
        |             |
  T --> |   function  | --> R
        |_ _ _ _ _ _ _| 

后者使用任何类型的对象,就像Predicate&lt;T&gt; 启用的那样,但可以在返回类型中变化

Predicate&lt;T&gt;Function&lt;T, R&gt; 的用例

Predicate&lt;T&gt; 的用例是当您需要一个函数,该函数使用一个 T 类型的参数并返回一个布尔值。例如这可能是在您想要过滤元素流的情况下,从满足.filter(predicate).findFirst() 等条件的流中找到第一个元素,或者检查满足特定条件的流中是否存在元素比如anyMatchnoneMatchallMatch等。

Function&lt;T, R&gt; 的用例是当您需要一个函数,该函数使用 T 类型的一个参数并将其转换为 R 类型,例如可能是在调用stream.map(func) 时。

你的代码sn-p解释:

关于您帖子中的示例 sn-p Predicate&lt;String&gt;Function&lt;String, Boolean&gt; 在它们所代表的方面是相同的,即它们都代表一个函数,采用 String 并返回 boolean。但是,前者避免将返回值从boolean 装箱到Boolean,而后者则不会。

也就是说,这并不一定意味着您可以在任何地方使用Predicate&lt;String&gt;,也可以使用Function&lt;String, Boolean&gt;,反之亦然。

示例:

编译时:

Predicate<String> predicate = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(predicate);

这不是:

Function<String, Boolean> function = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(function);

反之亦然:

虽然这有效:

Function<String, Boolean> function = p -> p.length() == 21;
Stream<Boolean> stream = stringList().stream().map(function);

这不是:

Predicate<String> predicate = p -> p.length() == 21;
Stream<Boolean> stream = stringList().stream().map(predicate);

【讨论】:

  • 您还可以提到Predicate 具有默认方法and()or()negate(),它们对条件有意义,而Function 上的默认方法对过滤/更有意义/链接。
  • @JensBannmann 这是一个重要的(实用的!)点。比其他答案中的挥手喋喋不休更相关(当他们说有〜“没有区别”时,基本上是错误的......)。考虑将此添加为(正确的!)答案。否则,我会试一试...
  • @JensBannmann 感谢您的反馈。直到今晚晚些时候,我才能将其整合到我的答案中,但如果需要,请随时编辑答案并改进它。或者,如果您愿意,您也可以按照 Marco 的建议发布您自己的答案。 :)
  • @Marco13 和 Aominè:好主意,我把它变成了an answer
  • @Eugene 这就像有人创建一个新的List 和一个新的Set,打印他们的size(),然后问有什么区别。当然,没有:两者的大小都是0。说在这种情况下“没有区别”可能不是“错误的”(我认为我们不必为此争论),但在非常 最少。在这两种情况下,我们都在用不同的方法讨论不同的类型,我认为从用法的角度明确它们的区别很重要。
【解决方案2】:

在这种情况下没有区别,它只对你可以申请的东西很重要。例如allMatch 需要Predicate,你不能传递Function,即使在逻辑上他们做同样的事情。

【讨论】:

  • 使用myFunction::apply 可能仍然有效
  • @Lino 是的,它会,但代表用户会有点额外
  • 虽然这可能不是“讨论”事情的正确场所(如果您愿意,我们可以进行聊天)。但是鉴于您对其他答案的 cmets,this 答案可能至少会提出为什么首先存在不同接口的问题(我认为这是一个很好的问题,有一些有趣的技术怪癖) .可以这么说,他们本可以省略Predicate,而只是在anyMatch 等方法中期望Function&lt;T, Boolean&gt;。 (暂时将null 问题放在一边)。
  • @Marco13 不知道为什么,但 IIRC 最初是 Block 两个 Predicate/Function,但我希望我没记错
【解决方案3】:

Aominè 的回答涵盖了基本差异。我想补充一点,这两个接口也有不同的专用默认方法,即您可以在任何实现类上调用的方法:

  • Predicate&lt;T&gt;
    • Predicate&lt;T&gt; and(Predicate&lt;? super T&gt; other) - 返回一个组合谓词,表示此谓词与另一个谓词的短路逻辑与。
    • Predicate&lt;T&gt; or(Predicate&lt;? super T&gt; other) - 返回一个组合谓词,表示此谓词与另一个谓词的短路逻辑 OR。
    • negate() - 返回一个表示该谓词的逻辑否定的谓词。
  • Function&lt;T,R&gt;
    • &lt;V&gt; Function&lt;T,V&gt; andThen(Function&lt;? super R,? extends V&gt; after) - 返回一个组合函数,该函数首先将此函数应用于其输入,然后将after 函数应用于结果。
    • &lt;V&gt; Function&lt;V,R&gt; compose(Function&lt;? super V,? extends T&gt; before) - 返回一个组合函数,该函数首先将 before 函数应用于其输入,然后将此函数应用于结果。

如您所见,Predicate 具有创建复杂条件的有用方法,就像您在常规 if 语句中使用的运算符一样,而 Function 具有支持简单链接的方法。

【讨论】:

  • 我不知道这有什么关系,当然他们有不同的方法、名称和目的。对我来说,这是牵线搭桥
【解决方案4】:

真的没有区别。

理论上,Predicate&lt;T&gt;Function&lt;T, Boolean&gt; 之间应该没有任何功能差异。 Predicate 只是一个函数,它接受某种类型的对象并返回一个布尔值。 Function 是一个泛化,它可以返回任何类型,而不仅仅是 Boolean's。

Java 本身可能存在使它们不同的实现细节,但理论上它们应该是相同的。

例如,如果接口只能接受 Predicate&lt;String&gt;,而不是 Function&lt;String, Boolean

【讨论】:

  • 这个答案似乎是假设性的,而不是基于证据的。有很多“理论上”“应该”等。考虑更好地研究你的答案并提供证据而不是推测。
  • @BoristheSpider 这不是假设。我不是在用“理论”来谈论我不理解的事情,而是用类型理论本身来谈论它。 Java 本身可能以不同于这些特性所基于的纯理论的方式实现它。
【解决方案5】:

虽然是老帖子,但我会为新手总结它们之间的差异

谓词:要实现条件检查我们应该使用谓词

函数:要执行某些操作并返回一些结果我们应该使用函数

谓词:谓词可以带一个类型参数,表示输入类型或实参类型。

功能:函数可以带2个类型参数第一个代表输入类型参数类型,第二个代表返回类型。

Predicate: Predicate 定义了一个名为 test() 的抽象函数。使用谓词时,您可以说“测试这个条件”或“测试这个条件”

函数:函数定义了一个抽象函数,叫做apply()。使用函数时可以说“应用这个函数”或“应用这个函数”

谓词:始终返回布尔值。

函数:函数可以返回任何类型的值。

有时人们称谓词为函数的特例。 它们之间的另一个区别是它们在各自的接口中包含不同类型的默认方法和静态方法

【讨论】:

  • 由我决定,谓词总是返回布尔值,函数可以返回任何东西,关键是不同。很好的总结
【解决方案6】:

Predicate 只能返回 booleantest() 的结果),而 Function 进行转换并可以返回任何内容(apply() 的结果)。

Predicate 用于测试条件。

Function 用于进行转换。

【讨论】:

    【解决方案7】:

    从技术角度来看,Predicate&lt;T&gt; 只是一个接收T 并返回布尔原始结果的函数。但是,从使用的角度来看,Predicate&lt;T&gt;Function&lt;T, Boolean&gt; 是完全不同的概念。

    我们使用Predicate&lt;T&gt; 执行过滤操作,例如在流管道中,我们采用大小为nStream&lt;T&gt;,使用Predicate&lt;T&gt; 对其进行过滤以获得大小小于或等于n。同时,流管道中的Function&lt;T, Boolean&gt;用于执行映射操作,将Stream&lt;T&gt;转换为Stream&lt;Boolean&gt;

    如您所见,Predicate&lt;T&gt;Function&lt;T, Boolean&gt; 在技术上是相同的(为简单起见,忽略包装器 Boolean),但是当放在特定的上下文中(例如流管道)时,它是完全不同的故事,因为他们每个人都扮演着不同的角色。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-02
      • 1970-01-01
      • 2018-07-01
      • 2014-03-17
      • 1970-01-01
      • 1970-01-01
      • 2020-02-02
      相关资源
      最近更新 更多