【问题标题】:Java Streams return throws error Unexpected return valueJava Streams返回抛出错误意外的返回值
【发布时间】:2021-07-29 09:34:12
【问题描述】:

我对 Java 流很陌生,我正在尝试使用流实现一种方法,但是当我尝试返回值时,它向我抛出了错误 Unexpected return value。我只是想知道我做错了什么。

以下是引发错误的Arrays.stream 值内的返回:

Object[] result = extensionBuilder((Map) extension.getValue());
Arrays.stream(result).forEach(innerExtension -> {
    return new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class, (JAXBElement) innerExtension);
});

但是,如果我尝试返回 Arrays.stream 之外的单个值,那么我可以获得第一个值。 (如您所见,我只返回第一个值 result[0]

Object[] result = extensionBuilder((Map) extension.getValue());
Arrays.stream(result).forEach(innerExtension -> {
    System.out.println((JAXBElement) innerExtension);
});
return new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class, (JAXBElement) result[0]);

我想将Object[] result中的值一一传递,并将结果返回给我的调用方法。

这是我拥有的完整方法:

  private Object[] extensionBuilder(Map<String, Object> extensions) {
    if (extensions == null) {
      return null;
    }
    return extensions.entrySet().stream().map(extension -> {
      if (extension.getValue() instanceof Map) {

        // return new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class,
        //    (JAXBElement) extensionBuilder((Map) extension.getValue())[0]);

        Object[] result = extensionBuilder((Map) extension.getValue());
        Arrays.stream(result).forEach(innerExtension -> {
          System.out.println((JAXBElement) innerExtension);
        });
        return new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class, (JAXBElement) result[0]);

      } else {
        return new JAXBElement<String>(new QName(getCleanLabel(extension.getKey())), String.class, extension.getValue().toString());
      }
    }).filter(Objects::nonNull).collect(Collectors.toList()).toArray(Object[]::new);
  }

这是给方法的输入:

{nameSpace:MyField-2={fb:My-Sub-Field-1={nameSpace:MyField-1=myValue, nameSpace:MyField-2=myValue, nameSpace:MyField-3=myValue}, nameSpace2:My-Sub-Field-2={nameSpace:MyField-4=myValue4, nameSpace:MyField-5=myValue5, nameSpace:MyField-6=myValue6}, nameSpace:MyField-7MyField-3=myValue1}, nameSpace:MyField-8=Name}

我对此有点困惑很长时间了。有人可以帮助我如何使用流完成返回概念吗?

基本上,我想返回 Object[] result 中每个元素的值,到目前为止,我只能为一个元素执行此操作,但我希望为 Object[] result 中存在的每个对象返回值

***** 5 月 11 日编辑 ******

根据对问题的回复,我可以做到,但我得到的回复看起来像这样:

<namespace:MainField>
    <namespace:SubField1>
        <namespace:Field1>Value1</namespace:Field1>
    </namespace:SubField1>
</namespace:MainField>
<namespace:MainField>
    <insta:SubField2>
        <insta:Field2>Value2</insta:Field2>
    </insta:SubField2>
</namespace:MainField>
<namespace:MainField>
    <namespace:SubField3>SubValue3</namespace:SubField3>
</namespace:MainField>
<namespace:MainField2>MainValue2</namespace:MainField2>
<namespace:MainField3>MainValue3</namespace:MainField3>

而我正在寻找这样的东西:

<namespace:MainField>
    <namespace:SubField1>
        <namespace:Field1>Value1</namespace:Field1>
    </namespace:SubField1>
    <insta:SubField2>
        <insta:Field2>Value2</insta:Field2>
    </insta:SubField2>
    <namespace:SubField3>SubValue3</namespace:SubField3>
</namespace:MainField>
<namespace:MainField2>MainValue2</namespace:MainField2>
<namespace:MainField3>MainValue3</namespace:MainField3>

这是由于streamObject[] result 中的每个元素返回JAXBElement 我想在完成循环子流后返回结果,如下所示:

  private Object[] extensionBuilder(Map<String, Object> extensions) {
    if (extensions == null) {
      return null;
    }
    return extensions.entrySet().stream().flatMap(extension -> {
      if (extension.getValue() instanceof Map) {
        // return Stream of result transformed to JAXBElements
        return Arrays.stream(extensionBuilder((Map) extension.getValue())).map(innerExtension -> {
          System.out.println(innerExtension);
          return new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class, (JAXBElement) innerExtension);
        });
      } else {
        return Stream.of(new JAXBElement<String>(new QName(getCleanLabel(extension.getKey())), String.class, extension.getValue().toString()));
      }
    }).filter(Objects::nonNull).collect(Collectors.toList()).toArray();
  }

我试过这个,但这给我带来了错误java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class javax.xml.bind.JAXBElement

有人可以帮助我修改Java Stream 以便获得预期的输出吗?

【问题讨论】:

    标签: java arrays java-8 return java-stream


    【解决方案1】:

    您正试图从传递给forEach 的lambda 返回一些值。那个 lambda 类型是 Consumer&lt;T&gt; 并且它的方法 accept 返回类型是 void 所以你不能从它返回任何值。

    如果你想从你的方法返回对象集合,我建议重写它以返回Stream

      private Object[] extensionBuilder(Map<String, Object> extensions) {
        if (extensions == null) {
          return null;
        }
        //                        use flatMap vvvvvvv instead of map
        return extensions.entrySet().stream().flatMap(extension -> {
          if (extension.getValue() instanceof Map) {
            Object[] result = extensionBuilder((Map) extension.getValue());
            // return Stream of result transformed to JAXBElements
            return Arrays.stream(result).map(innerExtension -> {
              return new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class, (JAXBElement) result[0]);
            });
          } else {
            // return Stream of single item
            return Stream.of(
              new JAXBElement<String>(new QName(getCleanLabel(extension.getKey())), String.class, extension.getValue().toString())
            );
          }
        }).filter(Objects::nonNull).collect(Collectors.toList()).toArray();
      }
    

    请参阅Stream::flatMap docs。


    如果你只是内联它,你可以不处理 result 变量:

      private Object[] extensionBuilder(Map<String, Object> extensions) {
        if (extensions == null) {
          return null;
        }
    
        return extensions.entrySet().stream().flatMap(extension -> {
          if (extension.getValue() instanceof Map) {
            // return Stream of result transformed to JAXBElements
            return Arrays.stream(extensionBuilder((Map) extension.getValue()))
              .map(innerExtension -> new JAXBElement<JAXBElement>(
                 new QName(getCleanLabel(extension.getKey())),
                 JAXBElement.class,
                 (JAXBElement) result[0]
              ));
          } else {
            return Stream.of(
              new JAXBElement<String>(new QName(getCleanLabel(extension.getKey())), String.class, extension.getValue().toString())
            );
          }
        }).filter(Objects::nonNull).collect(Collectors.toList()).toArray();
      }
    

    但要小心,最好取一个更好的名字 对于这个变量,不仅仅是内联它, 因为它缺乏可读性(恕我直言)。

    【讨论】:

    • 感谢您抽出时间并提供您的回复。我实际上正在使用这种方法来创建JAXBElement@XmlAnyElement(lax="true"),因为我需要Object[]。因此我返回Object[] 而不是Stream。如果可能的话,你能指导我使用。 Object[] 作为回报?以下是JaxBElement 的文档:docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/…
    • 您好,感谢您的编辑和回复。如果我想在没有结果变量的情况下这样做,那我该怎么做?我尝试了很多东西,但我无法得到它。我收到错误 java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class javax.xml.bind.JAXBElement。我已经编辑了我的问题并提供了我尝试过的东西。如果可能的话,请您提供一些建议。
    • @BATMAN_2008 再次扩展了答案:)
    • @BATMAN_2008 不确定它是否有帮助,您可能需要针对此问题打开另一个问题。
    • 嗨,伙计,非常感谢您的快速回答和更新。现在,重复项已被删除,但如果您观察到XML 我已按预期输出发布,我将面临一个小问题,您会看到namespace:SubField1namespace:SubField2 都包含在单个namespace:MainField 中,但基于您的回答流返回innerExtension 的每个元素的值,因此它为每个子元素创建namespace:MainField,因此我根据child 计数多次获得namespace:MainField
    【解决方案2】:

    首先你应该使用map进行中间操作并返回结果,然后将结果收集到List

    Arrays.stream(result)
          .map(innerExtension -> new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class, (JAXBElement) innerExtension))
          .collect(Collectors.toList());
    

    在您的情况下,如果if 条件为真,您需要返回对象列表,否则仅返回一个对象。所以我建议在这两种情况下都返回对象列表,然后使用flatMap 来展平列表

    private Object[] extensionBuilder(Map<String, Object> extensions) {
    if (extensions == null) {
      return null;
    }
    return extensions.entrySet().stream().map(extension -> {
      if (extension.getValue() instanceof Map) {
    
        // return new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class,
        //    (JAXBElement) extensionBuilder((Map) extension.getValue())[0]);
    
        Object[] result = extensionBuilder((Map) extension.getValue());
        return Arrays.stream(result)
          .map(innerExtension -> new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class, (JAXBElement) innerExtension))
          .collect(Collectors.toList());
    
      } else {
        return Arrays.asList(new JAXBElement<String>(new QName(getCleanLabel(extension.getKey())), String.class, extension.getValue().toString()));
      }})
          .flatMap(List::stream)
          .toArray(Object[]::new);
    }
       
    

    【讨论】:

    • 非常感谢您的详细解释。我试过了,它正在工作并且能够得到结果。但唯一的问题是我看到重复的条目正在被添加。我尝试使用 distinct 但仍然能够获得重复的条目。我猜streams 中有些东西搞砸了,导致它返回重复的条目。你能告诉我为什么我得到重复的值而不是单个条目吗?
    • 您好,感谢您的编辑和回复。如果我想在没有结果变量的情况下这样做,那我该怎么做?我尝试了很多东西,但我无法得到它。我收到错误 java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class javax.xml.bind.JAXBElement。我已经编辑了我的问题并提供了我尝试过的东西。如果可能的话,请您提供一些建议。
    【解决方案3】:

    forEach 接受 Consumer 对象(它只接受一个参数但不返回任何东西)。但目前您正试图在forEach 中返回一个元素。如果要创建转换对象列表,请执行以下操作:

    Object[] result = extensionBuilder((Map) extension.getValue());
    Arrays.stream(result)
          .map(innerExtension -> new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class, (JAXBElement) innerExtension))
          .collect(Collectors.toList());
    
    });
    

    如果要返回 Object 数组而不是 List,请将 collect 语句替换为 toArray

    Arrays.stream(result)
          .map(innerExtension -> new JAXBElement<JAXBElement>(new QName(getCleanLabel(extension.getKey())), JAXBElement.class, (JAXBElement) innerExtension))
          .toArray();
    

    【讨论】:

    • 感谢您抽出宝贵时间回复。实际上,我想返回Object[] 并且不希望创建List。由于调用应用程序期望返回 Object[]。如果可能的话,请指导我如何返回Object[]
    • @BATMAN_2008 代替 collect 语句,使用 toArray。我已经更新了我的答案
    • 您好,感谢您的编辑和回复。如果我想在没有 result 变量的情况下这样做,那我该怎么做?我尝试了很多东西,但我无法得到它。我收到错误java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class javax.xml.bind.JAXBElement。我已经编辑了我的问题并提供了我尝试过的东西。如果可能的话,请您提供一些建议。
    • @BATMAN_2008 不清楚“没有result 变量”的确切含义
    • 我已经用所有细节编辑了我的问题,因为很难在评论中提供细节。如果可能的话,请仔细研究一下,并在可能的情况下提供一些建议。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 1970-01-01
    • 2016-08-10
    相关资源
    最近更新 更多