理解 mapMulti 的问题
Issues understanding mapMulti
我对 Java 相当满意,我决定深入研究 API 的实现和使用,尤其是 Stream API。
在认为我做对了之后我做了一个实现,并且它起作用了。但是我意识到了一些让我烦恼的事情。
mapMulti函数接受参数a BiConsumer
:
default <R> Stream<R> mapMulti(BiConsumer<? super T, ? super Consumer<R>> mapper) {
Objects.requireNonNull(mapper);
return flatMap(e -> {
SpinedBuffer<R> buffer = new SpinedBuffer<>();
mapper.accept(e, buffer);
return StreamSupport.stream(buffer.spliterator(), false);
});
}
然后我想通过将我的元素 class 的接受函数传递给 mapMulti 函数来对其进行基准测试(这就是为什么我丢弃 s
的值,并且 ExecutionPlan 仅具有可用于基准测试的值JMH
public void mapMultiTest(ExecutionPlan exec){
Stream<Integer> s = exec.elts.stream().mapMulti(Element::accept);
}
这里是 Elementclass,它简单地将一个 int 分解为素数因子,并在消费者上调用 forEach。
public record Element(int value) {
public void accept(Consumer<Integer> consumer) {
decomp().forEach(consumer);
}
public ArrayList<Integer> decomp() {
ArrayList<Integer> list = new ArrayList<>();
int value = this.value;
while (!isPrime(value)) {
int prime = 2;
while (!isPrime(prime) || value % prime != 0)
prime++;
list.add(prime);
value /= prime;
}
list.add(value);
return list;
}
private boolean isPrime(int num) {
if (num <= 1) {
return false;
}
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
}
我的问题是:为什么我的 Element::accept(理论上是 mapper
arg)在不是 BiConsumer 类型时被认为是有效的,并且只接受一个参数,即使它是在 mapMulti 内部调用,它接受元素和缓冲区参数。
我可能完全遗漏了一些明显的东西或者对这些功能有错误的理解,但我在理解 BiConsumer, Consumer, Functions, BiFunctions
等方面遇到了一些麻烦
在此先感谢,我希望我能理解这类我觉得非常有趣的主题,尤其是所有这些 API 的开发方式。
因此,正如 @Thomas Kläger 在评论中指出的那样
Element.accept() is an instance method. To call it, you need two
objects: an Element instance and a Consumer consumer. Method
references are smart enough to detect this as a BiConsumer<Element,
Consumer consumer
所以
elts.stream().<Integer>mapMulti((elt,cons)->{
elt.accept(cons);
})
和
elts.stream().<Integer>mapMulti(Element::accept)
是一样的东西
非常感谢!
我对 Java 相当满意,我决定深入研究 API 的实现和使用,尤其是 Stream API。
在认为我做对了之后我做了一个实现,并且它起作用了。但是我意识到了一些让我烦恼的事情。
mapMulti函数接受参数a BiConsumer
:
default <R> Stream<R> mapMulti(BiConsumer<? super T, ? super Consumer<R>> mapper) {
Objects.requireNonNull(mapper);
return flatMap(e -> {
SpinedBuffer<R> buffer = new SpinedBuffer<>();
mapper.accept(e, buffer);
return StreamSupport.stream(buffer.spliterator(), false);
});
}
然后我想通过将我的元素 class 的接受函数传递给 mapMulti 函数来对其进行基准测试(这就是为什么我丢弃 s
的值,并且 ExecutionPlan 仅具有可用于基准测试的值JMH
public void mapMultiTest(ExecutionPlan exec){
Stream<Integer> s = exec.elts.stream().mapMulti(Element::accept);
}
这里是 Elementclass,它简单地将一个 int 分解为素数因子,并在消费者上调用 forEach。
public record Element(int value) {
public void accept(Consumer<Integer> consumer) {
decomp().forEach(consumer);
}
public ArrayList<Integer> decomp() {
ArrayList<Integer> list = new ArrayList<>();
int value = this.value;
while (!isPrime(value)) {
int prime = 2;
while (!isPrime(prime) || value % prime != 0)
prime++;
list.add(prime);
value /= prime;
}
list.add(value);
return list;
}
private boolean isPrime(int num) {
if (num <= 1) {
return false;
}
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
}
我的问题是:为什么我的 Element::accept(理论上是 mapper
arg)在不是 BiConsumer 类型时被认为是有效的,并且只接受一个参数,即使它是在 mapMulti 内部调用,它接受元素和缓冲区参数。
我可能完全遗漏了一些明显的东西或者对这些功能有错误的理解,但我在理解 BiConsumer, Consumer, Functions, BiFunctions
等方面遇到了一些麻烦
在此先感谢,我希望我能理解这类我觉得非常有趣的主题,尤其是所有这些 API 的开发方式。
因此,正如 @Thomas Kläger 在评论中指出的那样
Element.accept() is an instance method. To call it, you need two objects: an Element instance and a Consumer consumer. Method references are smart enough to detect this as a BiConsumer<Element, Consumer consumer
所以
elts.stream().<Integer>mapMulti((elt,cons)->{
elt.accept(cons);
})
和
elts.stream().<Integer>mapMulti(Element::accept)
是一样的东西
非常感谢!