`Stream.collect`与`StringBuilder`一起使用是有效的,但自定义类不起作用。

huangapple go评论73阅读模式
英文:

Stream.collect with StringBuilder works but Custom class is not working

问题

// S#1. 使用 StringBuilder 处理流
System.out.println(
    Stream.of("a", "b", "c", "d", "ef", "ghi", "j")
        .collect(StringBuilder::new,
                 StringBuilder::append,
                 StringBuilder::append)
        .toString()
);

// S#2. 使用流处理 Int 类型
// 自定义的类符合 collect 方法的参数类型
// 方法签名: collect(Supplier, accumulator, combiner)
Int anInt = new Int();
System.out.println(
    Stream.of("a", "b", "c", "d", "ef", "ghi", "j")
        .collect(() -> anInt, Int::accumulator, Int::combiner)
        .total
);
class Int {
  int total;
  static void accumulator(Int result, String str) { result.total += str.length(); }
  static void combiner(Int a, Int b) { a.total += b.total; }
}

// S#3. 使用 Int2 编译出错
// 我创建的自定义类具有类似于 StringBuilder 的 append(String) 的 accumulator 方法
// 就像在 S#1 中使用的 StringBuilder::append 一样
Int2 int2 = new Int2();
System.out.println(
    Stream.of("a", "b", "c", "d", "ef", "ghi", "j")
        .collect(() -> int2, int2::accumulator, int2::combiner)
);
class Int2 {
  void accumulator(String s) {}
  void combiner(Int2 b) {}
}

注:这只是你提供的代码的中文翻译,我没有添加任何额外的内容。

英文:
    // S#1. stream works with StringBuilder 
System.out.println( 
Stream.of("a", "b", "c", "d", "ef", "ghi", "j")
.collect(StringBuilder::new,
StringBuilder::append,
StringBuilder::append)
.toString()
);
// S#2. stream works fine with Int 
// my custom class that conforms to arg types of collect method
// method signature: collect(Supplier, accumulator, combiner)
Int anInt = new Int();
System.out.println(
Stream.of("a", "b", "c", "d", "ef", "ghi", "j")
.collect(() -> anInt, Int::accumulator, Int::combiner)
.total
);
class Int {
int total;
static void accumulator(Int result, String str) { result.total += str.length(); }
static void combiner(Int a, Int b) { a.total += b.total; }
}
// S#3. compiler error with Int2 
// custom class I created which has method accumulator(String) similar to StringBuidler append(String)
// StringBuilder::append (used as above in S#1)
Int2 int2 = new Int2();
System.out.println(
Stream.of("a", "b", "c", "d", "ef", "ghi", "j")
.collect(() -> int2, int2::accumulator, int2::combiner)
);
class Int2 {
void accumulator(String s) {}
void combiner(Int2 b) {}
}

But I am wondering how StringBuilder version code compiles, whereas S#3 (Int2 version) doesn't.
StringBuilder extends from CharSequence, AbstractStringBuilder classes. Is it working because of this hierarchy relationship which something lacks on my custom class (Int2)

Much appreciated your help.

答案1

得分: 3

使用StringBuilder方法的方式与使用Int2方法的方式进行比较:

.collect(StringBuilder::new,
StringBuilder::append,
StringBuilder::append)
.collect(
() -> int2, 
int2::accumulator, 
int2::combiner)

显然,它们具有不同的形式。int2::accumulator指的是特定实例int2上的accumulator方法。然而,StringBuilder::append指的是append方法。这些是不同类型的方法引用。有关不同类型的方法引用的更多信息,请参见此页面上的“方法引用类型”。

您应该改为使用:

.collect(
Int2::new, 
Int2::accumulator, 
Int2::combiner)

int2::accumulator在文档中称为“特定对象的实例方法引用”,它指的是接受String并返回void的方法,因此可以传递给Consumer<String>。然而,collect期望第二个参数为BiConsumer<Int2, String>

因为Int2::accumulator不引用特定的Int2实例。在文档中,它被称为“特定类型的任意对象的实例方法引用”,它表示一个函数,接受Int2实例作为其第一个参数,以及accumulator通常接受的其他参数。这就是为什么您可以传递Int2::accumulator。类似的解释也适用于Int2::combiner

不用说,由于您的方法是空的,所以在运行时不会执行任何操作。

英文:

Compare the way that you are using the StringBuilder methods, with the way that you are using your Int2 methods:

.collect(StringBuilder::new,
StringBuilder::append,
StringBuilder::append)
.collect(
() -&gt; int2, 
int2::accumulator, 
int2::combiner)

Clearly, they are in different forms. int2::accumulator refers to the accumulator method on a specific instance of Int2 called int2. StringBuilder::append however, refers to the append method. These are different kinds of method references. For more info about the different kinds of method references, see "Kinds of Method References" in this page.

You should instead use:

.collect(
Int2::new, 
Int2::accumulator, 
Int2::combiner)

int2::accumulator is known as a "Reference to an Instance Method of a Particular Object" in the docs, and it refers to a method that takes a String and returns void, so it can be passed into a Consumer&lt;String&gt;. However, collect expects BiConsumer&lt;Int2, String&gt; as the second argument.

Because Int2::accumulator does not refer to a specific instance of Int2. It is known as a "Reference to an Instance Method of an Arbitrary Object of a Particular Type" in the docs. It represents a function that accepts an instance of Int2 as its first parameter, in addition to the other parameters that accumulator normally accepts. This is why you can pass in Int2::accumulator instead. A similar explanation can be applied for Int2::combiner.

This goes without saying, but your methods are empty, so it won't do anything at runtime.

huangapple
  • 本文由 发表于 2020年9月5日 18:06:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/63752720.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定