【问题标题】:Process elements of Set<Foo> and create Set<Bar> using streams处理 Set<Foo> 的元素并使用流创建 Set<Bar>
【发布时间】:2017-10-21 12:29:15
【问题描述】:

我有一个 Set&lt;String&gt;"hostname:port" 对,我想从中创建一个 Set&lt;InetSocketAddress&gt;。我试过了:

Set<InetSocketAddress> ISAAddresses = StrAddresses
    .stream().map(addr -> new InetSocketAddress(
        addr.split(":")[0],
        Integer.parseInt(addr.split(":")[1])));

但这会在 IntelliJ 中产生以下错误:

不兼容的类型。必需 Set&lt;InetSocketAddress&gt; 但“地图”是 推断为Stream&lt;R&gt;:不存在类型变量 R 的实例,所以 Stream&lt;R&gt; 符合 Set&lt;InetSocketAddress&gt;

我使用地图和 lambda 的方式一定有问题。

【问题讨论】:

  • “**不起作用”是什么意思?它不编译吗?它会输出错误的结果吗?请准确说明发生了什么。
  • 请注意,请遵守命名约定。变量名应始终以小写字母开头(方法名相同,类名只有驼峰式)。
  • @tom 你应该把它放在问题中,而不是作为评论。
  • 除了添加collect 调用之外,我建议使用两个map 调用以避免拆分两次。 .map(addr -&gt; addr.split(":")).map(arr -&gt; new InetSocketAddress(arr[0], Integer.parseInt(arr[1))
  • @PaulBoddington 好点,保存第二个split 电话。在我的回答中添加了这一点。

标签: java lambda java-8 java-stream


【解决方案1】:

Stream#map 函数不返回 Map。它将流中的当前元素转换(映射)到其他元素。因此,它使用 given transformation functionStream&lt;X&gt; 生成 Stream&lt;Y&gt;,该函数采用 X 并输出 Y

StrAddresses.stream()                           // String
    .map(addr -> new InetSocketAddress(
        addr.split(":")[0],
        Integer.parseInt(addr.split(":")[1]))); // InetSocketAddress

您以 Stream&lt;String&gt; 开头并以 Stream&lt;InetSocketAddress&gt; 结尾。

引用其documentation

返回一个给定函数应用到该流的元素的结果组成的流。


如果您想将该流转换为Set,您需要使用Stream#collect 方法,如下所示:

StrAddresses.stream()
    .map(addr -> new InetSocketAddress(
        addr.split(":")[0],
        Integer.parseInt(addr.split(":")[1])))
    .collect(Collectors.toSet());

实用方法Collectors.toSet() 返回一个收集器,用于优化优化的Set。例如,如果您明确想要HashSet,您可以使用它:

.collect(Collectors.toCollection(HashSet::new));

来自其documentation

对此流的元素执行可变归约操作。可变缩减是其中缩减的值是可变结果容器,例如ArrayList [...]


作为一个小提示,您目前每次拆分同一个元素两次:

addr.split(":")[0],                     // First
Integer.parseInt(addr.split(":")[1])))  // Second

您可以通过记住之前的值来保存额外的split 过程。在这种情况下,这可以通过使用第二个Stream#map 调用来优雅地完成。首先我们从Stream&lt;String&gt; 转换为Stream&lt;String[]&gt; 再转换为Stream&lt;InetSocketAddress&gt;

StrAddresses.stream()                                 // String
    .map(addr -> addr.split(":"))                     // String[]
    .map(addrData -> new InetSocketAddress(
        addrData[0], Integer.parseInt(addrData[1])))  // InetSocketAddress
    .collect(Collectors.toSet());

注意Stream#map 是一个惰性操作。这意味着一旦您调用该方法,Java 将不会转换整个 StreamAB。它将等到像Stream#collect 这样的非惰性(最终确定)操作出现,然后遍历Stream 并应用每个惰性操作 element-wise。因此,您可以根据需要添加任意数量的Stream#map 调用,而不会在整个Stream 上产生额外循环

【讨论】:

  • 感谢您的详细解释。
【解决方案2】:

您需要collect映射到Set后返回的InetSocketAddress地址中的Stream。这可以作为 -

Set<InetSocketAddress> ISAAddresses = StrAddresses.stream()
                  .map(addr -> new InetSocketAddress(addr.split(":")[0], Integer.parseInt(addr.split(":")[1])))
                  .collect(Collectors.toSet());

【讨论】:

    猜你喜欢
    • 2010-12-03
    • 2020-03-11
    • 1970-01-01
    • 2017-02-28
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多