【问题标题】:Is there a way to use conditional predicate on a Java stream?有没有办法在 Java 流上使用条件谓词?
【发布时间】:2021-10-22 03:36:36
【问题描述】:

我使用 Java 8,我有一个字符串列表,我想提取匹配(或不匹配)正则表达式的字符串:

switch (condition) {
    case "A":
         return myListOfString.stream().filter(myString -> myString.matches(myRegex)).findFirst();
    case "B":
         return myListOfString.stream().filter(myString -> !myString.matches(myRegex)).findFirst();
}

这两种情况下的代码完全相同,除了!“NOT”。我想根据条件提取匹配正则表达式的字符串或不匹配正则表达式的字符串。我确信可以在同一个流中使用 Predicate 执行此操作,但我不知道如何操作。

有没有一种方法可以做到这一点,而无需在一个流中复制代码?

【问题讨论】:

标签: java functional-programming java-stream predicate


【解决方案1】:

如果我正确理解了您的问题,那么您想在不同条件下使用相同的流吗?

只需将开关盒移动到过滤器中即可。

return myListOfString.stream().filter(myString -> {

switch (condition) {
    case "A":
         return myString.matches(myRegex);
    case "B":
         return !myString.matches(myRegex));
    default: 
         return false;
    }
}

}).findFirst();

或者为过滤器创建一个谓词。

var myPredicate = (myString) -> {
switch (condition) {
    case "A":
         return myString.matches(myRegex);
    case "B":
         return !myString.matches(myRegex));
    default: 
         return false;
    }
};

return myListOfString.stream().filter(myPredicate).findFirst();

【讨论】:

  • 你传递filter(myPredicate),因为它已经是一个谓词。
  • 您不能将varvar myPredicate = (myString) -> {… 之类的lambda 表达式一起使用。
【解决方案2】:

tl;博士

将您的输入分成两个列表,即通过谓词测试的列表和未通过测试的列表。在Map< Boolean , List< String > > 中收集这些列表。

List
.of( "dog" , "giraffe" , "cockatiel" , "cat" )
.stream()
.collect( 
    Collectors
    .partitioningBy( 
        word -> word.length() <= 3   // `Predicate` test. Looking for short words versus long words.
    ) 
)                                    // Returns a `Map< Boolean , List< String > >`.
.get(
    Boolean.TRUE
)                                    // Returns one of the two `List` objects contained in our map.
.toString()

[狗,猫]

Collectors.partitioningBy

作为commented by Abhijit Sarkar,您可以使用专门的Collector 创建一个映射,其中每个可能的Boolean 有两个键,每个值都是与您的谓词匹配或不匹配的输入列表。见Collectors.partitioningBy

Out 谓词正在测试包含三个或更少字符的短词:word -&gt; word.length() &lt;= 3

我们生成两个列表。短词(符合我们谓词测试的词)位于分配给Boolean.TRUE 键的列表中。长词(未通过谓词测试的词)位于分配给Boolean.FALSE 的列表中。

List< String > words = List.of( "dog" , "giraffe" , "cockatiel" , "cat" ) ;
Map< Boolean , List< String > > map = words.stream().collect( Collectors.partitioningBy( word -> word.length() <= 3 ) ) ;

转储到控制台。

System.out.println( "map = " + map ) ;
System.out.println( "short words = " + map.get( Boolean.TRUE ) ) ;

看到这个code run live at IdeOne.com

map = {false=[giraffe, cockatiel], true=[dog, cat]}

短词=[狗,猫]

【讨论】:

  • 当所有 OP 想要做的事情时,安静沉重是findFirst()...
【解决方案3】:

好吧,在问题结束之前,答案是传递一个要使用的谓词。

Predicate<String> predicate;
switch (condition) {
    case "A":
        predicate = myString -> myString.matches(myRegex);
    case "B":
        predicate = myString -> !myString.matches(myRegex);
}

return myListOfString.stream().filter(predicate).findFirst();

注意,我没有尝试编译,但它应该可以让您了解要点。

【讨论】:

  • 或者在最近的Java版本中,可以使用switch expression
  • 保持简单。
  • 您需要一个默认值,因为谓词可能尚未初始化。
  • 从 Java 11 开始,使用 Predicate.not: condition.equals( "A" ) ? predicate : Predicate.not( predicate )
  • 使用filter(predicate::test) 而不仅仅是filter(predicate) 是没有意义的。而switch 需要default,否则会出现错误,“predicate 可能尚未初始化”
猜你喜欢
  • 1970-01-01
  • 2018-09-13
  • 2019-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多