[英]Error Message in Java (Stream and Lambda Comprehension)
我被困了几个小时试图调试我的代码。
这是我收到的错误消息
Error:(8, 8) java: trump.Wall is not abstract and does not override abstract method get() in java.util.function.Supplier
这些是与该错误对应的类。 因此,当我运行DonalTrump
类DonalTrump
它给了我上面的错误消息。 显然是由于Wall
类。 以下是我的代码
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);
}
}
乍一看,我发现您的代码有2个问题:
您没有在要collect
的DonaldTrump
类的调用中指定Supplier<Wall>
,或者做错了。 使Wall
类实现Supplier<Wall>
接口是不正确的。 用现实生活的角度来思考:一堵墙本身就是供应商,这毫无意义。 相反,您应该使用与Supplier
接口匹配的lambda表达式,即,该表达式的工作方式就好像您正在实现 Supplier.get
方法一样。 这是() -> new Wall(width, height)
。
在Wall
类中, accept
和combine
方法都不应该是静态的。 此外, accept
不应revceive的实例Wall
,但只接受一个Brick
,将被放入这个Wall
。 同样, combine
方法仅应接受一个Wall
参数并将此参数与此Wall
。 也许您可以阅读The Java Tutorial中有关方法引用的课程 ,该课程清楚地解释了所有不同的方法引用类型以及何时使用它们中的每一种。
考虑这些因素意味着您应该对代码进行一些更改。
在您的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);
在您的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);
}
其中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;
}
考虑也删除get
方法,因为不再需要实现Supplier<Wall>
。
实际上,通过此代码修复和重构,您不再需要accept
和combine
方法。 在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);
编辑:这些更改的主要原因是您没有正确使用Stream.collect
方法。
Stream.collect
需要3个参数:
Wall
,流的元素是Brick
实例,因此供应商是() -> new Wall(width, height)
。 该供应商可能被视为空墙,即像是地面上开始砌砖的地方。 BiConsumer
,它接受两个参数:上一项的供应商返回的结构和流的元素。 此累加器双消耗者的契约是它必须将流的一个元素累加到累加的可变结构中。 在您的情况下,累积的可变结构是上面的供应商创建的Wall
,而流的元素是Brick
实例,因此累加器是Wall::lay
或使用lambda (wall, brick) -> wall.lay(brick)
。 可以将这种蓄能器看作是一名工人一个接一个地将砖砌成的墙壁。 BiConsumer
,它接受两个参数,两个参数都是部分填充的可变结构的实例(这些结构的类型与项目1的Supplier
提供的结构相同)。 当最终结构的创建可以并行化时,将使用此合并器,并且其合同是将第二个自变量结构合并(或合并,混合,链接或联接)到第一个自变量结构中。 在您的情况下,部分填充的可变结构是两个用砖块部分填充的Wall
实例,因此组合器是Wall::linkToThisWall
,或者使用lambda (leftWall, rightWall) -> leftWall.linkToThisWall(rightWall)
。 所有这些结合在一起的东西可能被看作是两个独立的工人并行工作,每个工人都在自己的墙壁上砌砖工作:一个工人从左边开始,另一个工人从右边开始; 当它们在中间相遇时,两个半墙合并为一个新的全墙。 至于为什么您的解决方案不正确...您的组合器是错误的。 您不应该创建一个新的空结构,并将作为参数提供的两个结构合并到这个新结构中。 相反,您应该将第二个参数结构合并到第一个参数结构中。 这就是为什么您的静态linkTwoWalls
方法不起作用的原因:您将两堵墙合并为新的墙,并且从该静态方法返回了这堵新墙。 但是,返回的墙已被丢弃,因为合并器必须是将第二个合并到第一个参数中的BiConsumer
。 (您实际上是BinaryOperator
,即您是从两个墙中创建一个新墙并将其返回,就像您将两个数字求和并得到另一个数字一样)。 但是,您没有使用并行流,因此从未使用过合并器。
您将需要覆盖Supplier接口的get
方法。
public Wall get(){
return this;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.