Java中的错误消息(流和Lambda理解)

Java中的错误消息(流和Lambda理解),java,lambda,java-8,java-stream,collectors,Java,Lambda,Java 8,Java Stream,Collectors,我在调试代码时被困了好几个小时 这是我收到的错误消息 错误:(8,8)java:trump.Wall不是抽象的,并且不重写java.util.function.Supplier中的抽象方法get() 这些是对应于该错误的类。因此,当我运行类DonalTrump时,它给出了上面的错误消息。显然,这是因为墙类。下面是我的代码 DonaldTrump package trump; import java.util.*; import java.util.stream.*; import java.u

我在调试代码时被困了好几个小时

这是我收到的错误消息

错误:(8,8)java:trump.Wall不是抽象的,并且不重写java.util.function.Supplier中的抽象方法get()

这些是对应于该错误的类。因此,当我运行类
DonalTrump
时,它给出了上面的错误消息。显然,这是因为
类。下面是我的代码

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);
    }
}

您需要重写供应商接口的方法

public Wall get(){
      return this;
}

乍一看,我发现您的代码有两个问题:

  • DonaldTrump
    类中调用
    collect
    时,您没有指定
    供应商
    ,或者您做得不对。让您的
    Wall
    类实现
    Supplier
    接口是不正确的。从现实生活的角度考虑:墙本身就是供应商是没有道理的。相反,您应该使用与
    Supplier
    接口匹配的lambda表达式,也就是说,该表达式的工作原理与实现
    Supplier.get
    方法类似。这是
    ()->新墙(宽度、高度)

  • Wall
    类中,
    accept
    combine
    方法都不应该是静态的。此外,
    accept
    不应重新接收
    Wall
    的实例,而应只接受一个
    Brick
    ,它将被放入此
    Wall
    中。另外,
    combine
    方法应只接受一个
    Wall
    参数,并将此参数与此
    Wall
    组合。也许您可以阅读,它清楚地解释了所有不同的方法引用类型以及何时使用它们

  • 考虑到这些项目意味着您应该对代码进行一些更改

    在您的
    DonaldTrump
    类中,将
    ()->新墙(宽度、高度)
    lambda表达式作为
    收集方法的
    供应商

    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);
    
    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;
    }
    
    在您的
    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
    将是您的(现在无用的)
    linktotwowall
    方法的修改版本:

    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);
    
    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

    实际上,通过这种代码修复和重构,您不再需要
    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);
    
    EDIT:这些更改的主要原因是您没有正确使用
    流。collect
    方法

    Stream.collect
    需要3个参数:

  • 一个供应商,用于创建一个累积的、可变的结构,在其中累积流的元素。在您的代码中,此结构是一个
    ,流的元素是
    砖的实例
    ,因此供应商是
    ()->新墙(宽度、高度)
    。该供应商可能被视为一堵空墙,也就是说,就像地面上开始砌砖的地方
  • 一种累加器,它是一个
    双消费者
    ,接受两个参数:前一个项目的供应商返回的结构和流的一个元素。这个累加器双消费者的契约是,它必须将流中的一个元素累加到累加的可变结构中。在您的情况下,累积的可变结构是上面的供应商创建的
    ,流的元素是
    ,因此累加器是
    墙::铺
    ,或者使用lambda
    (墙,砖)->墙。铺(砖)
    。这个蓄能器可以被看作是一个工人一个接一个地往墙上砌砖
  • 一种组合器,它是一个接受两个参数的
    双消费者
    ,两个参数都是部分填充的可变结构的实例(这些结构的类型与
    供应商
    提供的第1项结构相同)。当最终结构的创建可以并行化,并且其契约是将第二个参数结构合并(或合并、混合、链接或连接)到第一个参数结构时,将使用此组合器。在您的例子中,部分填充的可变结构是两个用砖块部分填充的
    Wall
    实例,因此组合器是
    Wall::linkToThisWall
    ,或者使用lambda
    (leftWall,rightWall)->leftWall.linkToThisWall(rightWall)
    。所有这些结合在一起的东西可以被看作是两个独立的工人并行工作,每个人都在自己的墙上砌砖:一个工人从左边开始,另一个从右边开始;当它们在中间相遇时,这两个半墙被组合成一个新的完整的墙。
  • 至于为什么你的解决方案不正确。。。你的组合器错了。您不应该创建一个新的空结构,并将作为参数提供的两个结构合并到此新结构中。相反,您应该将第二个参数结构合并到第一个参数结构中。这就是为什么静态
    linkTwoWalls
    方法不起作用的原因:您将两堵墙合并为一堵新墙,并从该静态方法返回这堵新墙。但是,返回的wall被丢弃,因为合并器必须是一个将第二个参数合并到第一个参数中的
    BiConsumer
    。(您的操作实际上是一个
    二进制运算符
    ,也就是说,您正在从两个墙创建一个新墙并返回它,就像您将两个数字相加并得到另一个数字一样)。但是,您没有使用并行流,因此从未使用过合并器

    你说的是密码