如何在Java 8中引用reduce()操作的结果?

如何在Java 8中引用reduce()操作的结果?,java,scala,lambda,java-stream,reduce,Java,Scala,Lambda,Java Stream,Reduce,我试图用Java8编写一个mkString函数,这是一个la Scala的有用mkString,遇到了两个问题,我需要一些帮助: 我无法使mkString的第一个参数成为像Collection c这样的通用集合引用,并且无法让调用程序调用任何类型的集合 无法在线引用reduce()的返回结果以访问结果的长度以删除额外的前导分隔符 代码如下: public static void main(String[] args) { List<Integer> numbers = Arr

我试图用Java8编写一个
mkString
函数,这是一个la Scala的有用
mkString
,遇到了两个问题,我需要一些帮助:

  • 我无法使
    mkString
    的第一个参数成为像
    Collection c
    这样的通用集合引用,并且无法让调用程序调用任何类型的集合

  • 无法在线引用
    reduce()
    的返回结果以访问结果的长度以删除额外的前导分隔符

  • 代码如下:

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        System.out.println(mkString(numbers, ","));
    
    }
    
    public static String mkString(Collection<Integer> c, String sep) {
        return c.stream()
                .map(e -> String.valueOf(e))
                .reduce("", (a, b) -> a + sep + b)
                .substring(1, <<>>.length);
    }
    
    publicstaticvoidmain(字符串[]args){
    列表编号=数组.asList(1,2,3,4,5);
    System.out.println(mkString(数字,“,”);
    }
    公共静态字符串mkString(集合c,字符串sep){
    返回c.stream()
    .map(e->String.valueOf(e))
    .reduce(“,(a,b)->a+sep+b)
    .子串(1,长度);
    }
    
    如果我正确地记住了java,您可以将参数类型声明为
    Collection
    ,以便能够传递任何对象的集合

    至于咬掉分隔符,我想,只要
    。子字符串(1)
    就可以了。

    你可以这样做:

    public static <T>  String mkString(Collection<T> c, String sep) { // generic impl
        return c.stream()
                .map(String::valueOf)
                .reduce("", (a, b) -> a + sep + b)
                .substring(1); // substring implementation to strip leading character
    }
    
    公共静态字符串mkString(集合c,字符串sep){//generic impl
    返回c.stream()
    .map(字符串::valueOf)
    .reduce(“,(a,b)->a+sep+b)
    .substring(1);//剥离前导字符的子字符串实现
    }
    

    注意,如果你这样做不是为了自我教育,而是在一些生产代码中实际使用它,那么你可能需要考虑内置的收集器:

    String result = numbers.stream()
        .map(Object::toString)
        // or
        //   .map(x -> x.toString())  // exactly the same
        // or
        //   .map(String::valueOf)    // handles nulls by turning them to the string "null"
        .collect(Collectors.joining(","));
    
    它有几个重载,类似于Scala的
    mkString
    。不过,此收集器只接受
    CharSequence
    s,因此您需要将值显式转换为字符串,作为一个单独的
    map
    步骤

    此外,还有一种方法,它也适用于
    CharSequence
    s的集合。如果您特别拥有其中一个(例如,
    列表
    ),则使用此方法可能比先将集合转换为流更方便:

    List<String> strings = ...;
    
    String result = String.join(",", strings);
    
    // vs
    
    String result = strings.stream().collect(Collectors.joining(","))
    
    列出字符串=。。。;
    字符串结果=String.join(“,”字符串);
    //vs
    字符串结果=strings.stream().collect(收集器.连接(“,”))
    
    您可以使用
    字符串。使用泛型类型连接

    public static <T> String mkString(Collection<T> c, String sep) {
        return String.join(sep, c.stream()
                                 .map(e -> String.valueOf(e))
                                 .collect(Collectors.toList()));
    }
    
    公共静态字符串mkString(集合c,字符串sep){
    返回String.join(sep,c.stream()
    .map(e->String.valueOf(e))
    .collect(Collectors.toList());
    }
    
    与字符串和其他对象一起使用。

    java中的任何类型的集合都意味着
    集合
    ,它在语义上与
    集合
    (在您的情况下)相同,如果类型参数只使用一次,则可以安全地用通配符替换它。但是,由于您希望能够压缩任何集合,因此还应该要求调用方提供一个
    函数
    ,该函数将从该类型转换为字符串表示,因此您的方法将变成:

    public static <T> String mkString(Collection<T> c,
                                      Function<T, ? extends CharSequence> mapper,
                                      String sep) {
        return c.stream()
                .map(mapper)
                .collect(Collectors.joining(sep));
    
    }
    
    公共静态字符串mkString(集合c、,
    函数映射器,
    字符串(sep){
    返回c.stream()
    .map(mapper)
    .收集(收集器.连接(sep));
    }
    
    感谢您解决这两个问题。但是,这是否意味着没有语法来访问reduce()的结果而不进行赋值?
    T
    <代码>集合
    也可以工作。@nullpointer这不是关联的,因此违反了规范。。。您希望从
    String s=Stream.of(“a”、“b”、“c”、“d”).parallel()中打印什么;系统输出打印项次例如?@212好吧,这主要取决于您要执行的操作,我会说。@nullpointer,即使您不确定是否需要:1)文档强制执行它2)尝试我上面给出的代码并查看结果-但首先尝试看看您是否能预测它与集合相比似乎更倾向于泛型方法方法。
    T
    在这种情况下是完全相同的。所以,这是品味的问题。我个人更喜欢
    ,因为它清楚地表明,实现不使用或不需要类型信息,并且集合是要进行变异的。这也是呼叫站点差异的一个常见指标。@212:我想你一定是看错了链接到的页面。在“返回类型不依赖于类型参数,也不依赖于该方法的任何其他参数”的情况下,“应该使用通配符”,这一点非常明确,并为此指南专门提供了多个段落。因此,Dima是非常正确的。@用更简单的话来说,Dima(在有效的java中也存在IIRC):如果一个类型参数只使用一次,它可以被一个通配符替换。
    。如果分隔符由多个字符组成,使用reduce来构建字符串的效率非常低,子字符串(1)
    将无法工作。每个元素都需要累加器字符串的完整副本。最好使用一个专用的连接函数,它可以使用字符串生成器之类的东西。不过这不会编译<代码>收藏家::加入期待一个<代码>字符序列,你也需要提供一个如果你这样做是为了自我教育,考虑自己写一个等价的收集器(或者不是完全相同的来解决尤金提到的问题)。即使这个解决方案需要<代码>地图>代码>我仍然认为这是最好的解决方案,因为它是性能最好的,因为它在内部使用字符串生成器,而不是串联字符串。事实上,我没有注意到它需要
    CharSequence
    s,所以它实际上非常类似于
    string.join
    。我已经确定了我的答案