处理Set <foo>的元素并使用流创建Set <bar>

时间:2017-10-21 12:29:16

标签: java lambda java-8 java-stream

我有operator fun plus(other: PenceAmount): PenceAmount { // Get the primary constructor. val primaryConstructor = PenceAmount::class.primaryConstructor ?: throw NullPointerException("The primary constructor can't be found.") // Get the properties before the loop. val memberProperties = PenceAmount::class.declaredMemberProperties // Loop on each constructor parameter and get the new // values used to create a new instance of PenceAmount. val newValues = primaryConstructor.parameters.map { parameter -> // Find the KProperty with the same name of the parameter (because we are in a data class). val property = memberProperties.first { it.name == parameter.name } // Sum the amount. property.get(this) as Int + property.get(other) as Int } // Create a new instance of PenceAmount with the new values. return primaryConstructor.call(*newValues.toTypedArray()) } Set<String>对,我想创建一个"hostname:port"。我尝试过这样:

Set<InetSocketAddress>

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

  

不兼容的类型。必需Set<InetSocketAddress> ISAAddresses = StrAddresses .stream().map(addr -> new InetSocketAddress( addr.split(":")[0], Integer.parseInt(addr.split(":")[1]))); 但是'map'是   推断为Set<InetSocketAddress>:没有类型变量R的实例存在   Stream<R>符合Stream<R>

我使用地图和lambda的方式肯定是错的。

2 个答案:

答案 0 :(得分:10)

Stream#map功能不返回 a Map。它(映射)流的当前元素转换为其他元素。因此,它使用给定的 转换函数Stream<X> Stream<Y>生成,其中X和输出Y

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

您从Stream<String>开始,最后得到Stream<InetSocketAddress>

引用其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<String>转换为Stream<String[]>,然后转换为Stream<InetSocketAddress>

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就不会将StreamA转换为<{em} B。它会等到Stream#collect之类的非延迟(最终确定)操作,然后遍历Stream并应用每个延迟操作 逐元素即可。因此,您可以根据需要添加任意数量的Stream#map调用,而不会在整个Stream上生成额外循环

答案 1 :(得分:4)

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

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