[英]Error Message in Java (Stream and Lambda Comprehension)
I've been stuck for several hours trying to debug my code. 我被困了几个小时试图调试我的代码。
this is the error message that I get 这是我收到的错误消息
Error:(8, 8) java: trump.Wall is not abstract and does not override abstract method get() in java.util.function.Supplier
these are the classes that corresponds to that error. 这些是与该错误对应的类。 So when I run the class
DonalTrump
it gave me the error message above. 因此,当我运行
DonalTrump
类DonalTrump
它给了我上面的错误消息。 And apparently it is because of the Wall
class. 显然是由于
Wall
类。 The following is my code 以下是我的代码
DonaldTrump
package trump;
import java.util.*;
import java.util.stream.*;
import java.util.function.BiConsumer;
public class DonaldTrump{
public static void main(String[] args) {
if (args.length < 3) {
System.out.println("Need three integer arguments: width height #bricks");
System.exit(1);
}
int width = Integer.parseInt(args[0]);
int height = Integer.parseInt(args[1]);
int numberOfBricks = Integer.parseInt(args[2]);
assert numberOfBricks <= width * height: "Too many bricks";
System.out.printf("Will build a wall %d wide and %d tall%n",
width, height);
System.out.println(String.join("", Collections.nCopies(width,"==")));
Wall trumpWall
= Stream.generate(() -> new Ball(10.0))
.filter(b -> b.colour == Ball.Colour.RED)
.map(Brick::new)
.limit(numberOfBricks)
.collect(() -> new Wall(width, height), Wall::accept, Wall::combine); //UPDATE
System.out.println(trumpWall);
}
}
//Wall SOURCE OF ERROR HERE
package trump;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.*;
public class Wall implements Supplier<Wall> { //ERROR HERE//
public Wall get() { //UPDATE
return this;
}
private Brick[][] bricks;
private int width;
private int height;
private int lastFilledX;
private int lastFilledY;
private boolean isComplete;
final String sideBrick = "\u2b1b";
final String innerBrick = " \u2b1b"; // black box (brick) in Unicode
public Wall(int w, int h) {
assert w > 0 && h > 0 : "the wall must have finite width and height";
this.width = w;
this.height = h;
this.bricks = new Brick[width][height];
for (int j = 0; j < this.height; j++)
for (int i = 0; i < this.width; i++)
this.bricks[i][j] = null;
this.lastFilledX = 0;
this.lastFilledY = 0;
// this.isComplete = false;
}
public void lay(Brick brick) {
if (this.isComplete()) return;
this.bricks[lastFilledX][lastFilledY] = brick;
// if (this.isComplete()) return false;
if (this.lastFilledX == this.width - 1) {
this.lastFilledX = 0;
this.lastFilledY += 1;
} else {
this.lastFilledX += 1;
}
}
public boolean isComplete() {
return Stream.of(this.bricks).allMatch(
level -> Stream.of(level).allMatch(b -> b != null));
// return (this.lastFilledX == this.width - 1 &&
// this.lastFilledY == this.height - 1);
}
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
for (int j = this.height - 1; j >= 0; j--) {
for (int i = 0; i < this.width; i++)
// try any from the range u25a2 -- u25a9
buffer.append(bricks[i][j] == null ? " " :
i == 0 ? sideBrick : innerBrick);
// buffer.append(bricks[i][j] == 0 ? "0" : "1");
buffer.append("\n");
}
// return "\033[31m" + buffer.toString() + "\033[0m";
return buffer.toString(); // to hell with color code sequence
}
public static Wall linkTwoWalls(Wall w1, Wall w2) {
assert w1.height == w2.height : "Walls have unequal height";
if (!w1.isComplete() || !w2.isComplete())
return null; //Optional.empty();
int w = w1.width + w2.width;
int h = w1.height;
Brick[][] bricks = new Brick[w][h];
System.arraycopy(w1, 0, bricks, 0, w1.width);
System.arraycopy(w2, w1.width, bricks, 0, w2.width);
Wall result = new Wall(w, h);
result.bricks = bricks;
return result;//Optional.of(result);
}
public static Optional<Wall> joinWalls(Wall... walls) {
if (walls == null || walls.length == 0)
return Optional.empty();
// check all walls are of the same height
int firstHeight = walls[0].height;
Stream<Wall> wallStream = Stream.of(walls);
assert wallStream.allMatch(w -> w.height == firstHeight);
return wallStream.reduce((w1, w2) -> linkTwoWalls(w1, w2));
}
public void accept(Wall wall, Brick brick) { //UPDATE NOT STATIC
wall.lay(brick);
}
public void combine(Wall w1, Wall w2) { //UPDATE NOT STATIC
Wall.linkTwoWalls(w1, w2);
}
public static void main(String[] args) {
Wall wall = new Wall(40, 10);
for (int i = 0; i < 411; i++) {
wall.lay(new Brick(new Ball(10.0)));
if (wall.isComplete())
break;
}
System.out.print(wall);
}
}
At first glance, I see 2 problems with your code: 乍一看,我发现您的代码有2个问题:
You are not specifying a Supplier<Wall>
in the call to collect
in the DonaldTrump
class, or you are doing it wrong. 您没有在要
collect
的DonaldTrump
类的调用中指定Supplier<Wall>
,或者做错了。 It's not correct to make your Wall
class implement the Supplier<Wall>
interface. 使
Wall
类实现Supplier<Wall>
接口是不正确的。 Think of it in real life terms: it doesn't make sense that a wall is a supplier of itself. 用现实生活的角度来思考:一堵墙本身就是供应商,这毫无意义。 Instead, you should use a lambda expression that matches the
Supplier
interface, ie one that works as if you were implementing the Supplier.get
method. 相反,您应该使用与
Supplier
接口匹配的lambda表达式,即,该表达式的工作方式就好像您正在实现 Supplier.get
方法一样。 This is () -> new Wall(width, height)
. 这是
() -> new Wall(width, height)
。
In your Wall
class, both the accept
and combine
methods shouldn't be static. 在
Wall
类中, accept
和combine
方法都不应该是静态的。 Besides, accept
should not revceive an instance of Wall
, but only accept a Brick
, which will be put into this Wall
. 此外,
accept
不应revceive的实例Wall
,但只接受一个Brick
,将被放入这个Wall
。 Also, the combine
method should accept only one Wall
argument and combine this argument with this Wall
. 同样,
combine
方法仅应接受一个Wall
参数并将此参数与此Wall
。 Maybe you could read the lesson about method references in The Java Tutorial , which clearly explains all the different method reference types and when to use each one of them. 也许您可以阅读The Java Tutorial中有关方法引用的课程 ,该课程清楚地解释了所有不同的方法引用类型以及何时使用它们中的每一种。
Taking these items into account means that you should perform a few changes to your code. 考虑这些因素意味着您应该对代码进行一些更改。
In your DonaldTrump
class, place the () -> new Wall(width, height)
lambda expression as the Supplier
of the collect
method: 在您的
DonaldTrump
类中,将() -> new Wall(width, height)
lambda表达式放置为collect
方法的Supplier
:
Wall trumpWall = Stream.generate(() -> new Ball(10.0))
.filter(b -> b.colour == Ball.Colour.RED)
.map(Brick::new)
.limit(numberOfBricks)
.collect(() -> new Wall(width, height), Wall::accept, Wall::combine);
And in your Wall
class, change the accept
and combine
method as follows: 在您的
Wall
类中,如下更改accept
和combine
方法:
public void accept(Brick brick) { // Lay a brick into THIS wall
this.lay(brick);
}
public void combine(Wall wanother) { // Combine another wall with THIS wall
this.linkToThisWall(another);
}
Where linkToThisWall
would be a modified version of your (now useless) linkTwoWalls
method: 其中
linkToThisWall
将是您的linkTwoWalls
方法(现在已无用)的修改版本:
public void linkToThisWall(Wall another) {
assert this.height == another.height : "Walls have unequal height";
if (!this.isComplete() || !another.isComplete()) {
return; // or maybe throw an exception?
}
int w = this.width + another.width;
int h = this.height;
Brick[][] newBricks = new Brick[w][h];
System.arraycopy(this.bricks, 0, newBricks, 0, this.width);
System.arraycopy(another.bricks, this.width, bricks, 0, another.width);
this.bricks = newBricks;
}
Consider also removing the get
method, as implementing Supplier<Wall>
is no longer needed. 考虑也删除
get
方法,因为不再需要实现Supplier<Wall>
。
Actually, with this code fix and refactoring, you no longer need the accept
and combine
methods. 实际上,通过此代码修复和重构,您不再需要
accept
和combine
方法。 In your DonaldTrump
class, you could just use references to the refactored lay
and linkToThisWall
methods instead: 在
DonaldTrump
类中,您可以只使用对重构的lay
和linkToThisWall
方法的引用:
Wall trumpWall = Stream.generate(() -> new Ball(10.0))
.filter(b -> b.colour == Ball.Colour.RED)
.map(Brick::new)
.limit(numberOfBricks)
.collect(() -> new Wall(width, height), Wall::lay, Wall::linkToThisWall);
EDIT: The main reason for these changes is that you were not using the Stream.collect
method correctly. 编辑:这些更改的主要原因是您没有正确使用
Stream.collect
方法。
Stream.collect
expects 3 arguments: Stream.collect
需要3个参数:
Wall
and the elements of the stream are instances of Brick
, so the supplier is () -> new Wall(width, height)
. Wall
,流的元素是Brick
实例,因此供应商是() -> new Wall(width, height)
。 This supplier might be seen as an empty wall, ie like a place in the ground where to start laying bricks. BiConsumer
that accepts two arguments: the structure returned by the previous item's supplier and an element of the stream. BiConsumer
,它接受两个参数:上一项的供应商返回的结构和流的元素。 The contract for this accumulator biconsumer is that it has to accumulate one element of the stream into the cumulative, mutable structure. Wall
created by the supplier above and the elements of the stream are instances of Brick
, so the accumulator is Wall::lay
, or using a lambda (wall, brick) -> wall.lay(brick)
. Wall
,而流的元素是Brick
实例,因此累加器是Wall::lay
或使用lambda (wall, brick) -> wall.lay(brick)
。 This accumulator might be seen as a worker laying bricks into a wall, one by one. BiConsumer
that accepts two arguments, both being instances of a partially filled, mutable structure (these structures have the same type as the structure supplied by the Supplier
of item 1). BiConsumer
,它接受两个参数,两个参数都是部分填充的可变结构的实例(这些结构的类型与项目1的Supplier
提供的结构相同)。 This combiner is to be used when the creation of the final structure can be parallelized, and its contract is to combine (or merge, or mix, or link or join) the second argument structure into the first argument structure. Wall
instances partially filled with bricks, so the combiner is Wall::linkToThisWall
, or using a lambda (leftWall, rightWall) -> leftWall.linkToThisWall(rightWall)
. Wall
实例,因此组合器是Wall::linkToThisWall
,或者使用lambda (leftWall, rightWall) -> leftWall.linkToThisWall(rightWall)
。 All this combining stuff might be seen as two separate workers working in parallel, each one working by laying bricks into his own wall: one worker would start on the left and the other one would start in the right; As to why your solution was incorrect... Your combiner was wrong. 至于为什么您的解决方案不正确...您的组合器是错误的。 You are not supposed to create a new, empty structure and merge the two structures provided as arguments into this new structure.
您不应该创建一个新的空结构,并将作为参数提供的两个结构合并到这个新结构中。 Instead, you should merge the second argument structure into the first argument structure.
相反,您应该将第二个参数结构合并到第一个参数结构中。 This is why your static
linkTwoWalls
method didn't work: you were merging two walls into a new one and you were returning this new wall from that static method. 这就是为什么您的静态
linkTwoWalls
方法不起作用的原因:您将两堵墙合并为新的墙,并且从该静态方法返回了这堵新墙。 However, that returned wall was being discarded, because the combiner must be a BiConsumer
that merges second into first argument. 但是,返回的墙已被丢弃,因为合并器必须是将第二个合并到第一个参数中的
BiConsumer
。 (Yours was actually a BinaryOperator
, ie you were creating a new wall from two walls and returning it, as when you sum two numbers and get another number as a result). (您实际上是
BinaryOperator
,即您是从两个墙中创建一个新墙并将其返回,就像您将两个数字求和并得到另一个数字一样)。 However, you were not using a parallel stream, so your combiner was never used. 但是,您没有使用并行流,因此从未使用过合并器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.