【问题标题】:Java 8 stream - or conditionJava 8 流 - 或条件
【发布时间】:2016-11-11 15:33:19
【问题描述】:

查看这段代码: (这是工作代码,但我不喜欢使用 2 行代码,所以寻找如何让它变得更好)

ItemDetails[] items = response.getDetailsList();
items = Arrays.stream(items).filter(x -> !x.getName().equalsIgnoreCase("acl1")).toArray(ItemDetails[]::new);
items = Arrays.stream(items).filter(x -> !x.getName().equalsIgnoreCase("acl2")).toArray(ItemDetails[]::new);

我不知道如何在filter 中使用OR (|) 条件从List 中删除两个特定元素,因为它会给我带来编译时错误(在IDE 中),我最终会使用两个filters 之类的更多。 我可能会错过什么?

这就是我尝试使用 OR 的方式

items = Arrays.stream(items).filter(x -> !x.getName().equalsIgnoreCase("acl1") ||
        x -> !x.getName().equalsIgnoreCase("acl2")).toArray(ItemDetails[]::new);

=> IntelliJ 会抱怨这个(上图)

items = Arrays.stream(items).filter(x -> !x.getName().equalsIgnoreCase("acl1"") ||
        x.getName().equalsIgnoreCase("acl2")).toArray(ItemDetails[]::new);

在运行时不起作用(不过滤)

带有注释代码的整个代码(我尝试过)以供参考

public static void mapTest () {

        AclDetailItem[] items = new AclDetailItem[3];

        AclDetailItem item1 = new AclDetailItem();
        item1.setAclName("acl1");

        AclDetailItem item2 = new AclDetailItem();
        item2.setAclName("acl2");

        AclDetailItem item3 = new AclDetailItem();
        item3.setAclName("acl3");

        items[0] = item1;
        items[1] = item2;
        items[2] = item3;

        System.out.println ("Before " + items.length);


        items = Arrays.stream(items).filter(x -> !x.getAclName().equalsIgnoreCase("acl1")).toArray(ItemDetails[]::new);
        items = Arrays.stream(items).filter(x -> !x.getAclName().equalsIgnoreCase("acl2")).toArray(ItemDetails[]::new);

        System.out.println ("After "  + items.length);
    }

【问题讨论】:

  • 什么错误?你尝试了什么?这很重要。
  • 我没有投反对票,但这是一个糟糕的问题。
  • items = Arrays.stream(items).filter(x -> !x.getName().equalsIgnoreCase("redirect") || x->!x.getName().equalsIgnoreCase("成功")).toArray(ItemDetails[]::new);
  • @Rockoder 请将其编辑为原始问题。
  • 删除你的第二个x->...

标签: java lambda java-8 java-stream


【解决方案1】:

您应该为每个条件创建多个谓词并使用 or 连接它。我添加了以下示例:

public class MeTest {

    Predicate<Integer> con1 = i -> i==0;
    Predicate<Integer> con2 = i -> i==1;
    Predicate<Integer> con3 = i -> i==2;

    @Test
    public void testOr() {
        List<Integer> asdas = IntStream.range(1, 10).boxed().filter(con1.or(con2).or(con3)).collect(toList());
        System.out.println("asdas = " + asdas);
    }
}

【讨论】:

  • 这通常是我的首选方法。它还允许实用程序类包含用于匹配的谓词,这非常好。
【解决方案2】:

第一个不正确,因为它的x -&gt; 太多。 第二个不会过滤,因为您构造了一个始终为true 的条件。只需在filter-方法中优化您的条件,它就会过滤。

编辑(问题得到详细说明): 我仍然认为,你的条件有问题。您可能希望同时排除 acl1acl2。如果是这样,您的情况应该类似于:

!(x.getAclName().equalsIgnoreCase("acl1") || x.getAclName().equalsIgnoreCase("acl2"))
// or if you prefer &&
!x.getAclName().equalsIgnoreCase("acl1") && !x.getAclName().equalsIgnoreCase("acl2")
// or if you prefer regular expressions/matches
!x.getAclName().matches("(?i)^acl[1|2]$")

【讨论】:

  • 谢谢!这完美地工作。如果这可以帮助其他人,有人可以支持我的问题!不知道为什么当它从人们那里吸引有效的 cmets 时它是 -1。
【解决方案3】:
items = Arrays.stream(items).filter(
    x -> !x.getName().equalsIgnoreCase("redirect")
    || x->!x.getName().equalsIgnoreCase("success"))
    .toArray(ItemDetails[]::new);

注意第二个x-&gt;。这用于在 lambda 的开头绑定一个变量。将它放在中间是无效的,并且没有必要,因为x 已经存在于范围中。只需删除该位:

items = Arrays.stream(items).filter(x ->
    !x.getName().equalsIgnoreCase("redirect")
    || !x.getName().equalsIgnoreCase("success"))
    .toArray(ItemDetails[]::new);

【讨论】:

  • 将测试这个答案并更新。我想我已经尝试了所有可能的排列,但没有奏效。我尝试了很多变体,最后放弃了使用我发布的解决方案,因为我想转移到下一个任务。
  • 更新:我的错,我搞砸了语法。现在它编译得很好。测试它。
  • 如果问题有效,请给大家点赞!它搞砸了我的徽章/等级
  • @Rockoder 我正在尝试在我的手机上操作代码,所以我的键盘可能在某处使用了语法。只需从过滤器 lambda 中删除第二个变量绑定。
  • 抱歉,在运行时不起作用。它不过滤。我在过滤之前和之后打印数组的长度,它们是相同的。这个想法是过滤原始数组。
【解决方案4】:

我有一个类似的问题:如何使用 Java 流来过滤满足 CONDITION_1 或 CONDITION_2 的对象子集。我想这将是在过滤器中包含这两个条件。

myListOfElms().stream()
  .filter(elm -> elm.condition1OK() || elm.condition2OK())
  .collect(toList());

当然,将这些条件包装在私有方法中会使其看起来更好。但这就是想法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    相关资源
    最近更新 更多