英文:
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(
() -> 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<String>
. However, collect
expects BiConsumer<Int2, String>
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论