Search code examples
javaarraylistawtgraphics2dmethod-reference

Graphics2D and GUI: ArrayList of methods, method reference error


Imagining I have an arrayList of three JButtons: b_line, b_rect, b_oval, whose functionalities are very similar - they draw line/rectangle/oval on the JFrame.

Instead of writing actionListener for all three of them manually, I am thinking about using ArrayList to assign their actionListeners - so create an arraylist of Graphic2D draw methods, like this:

{drawLine, drawRect, drawOval}

Below is my code:

ArrayList<Consumer<Void>> draws = new ArrayList<>();
draws.add(Graphics2D::drawLine);

The error occurs saying that drawline is static method and it should not be used in this context.

How can I modify the method reference to support the drawLine method? Thank you for helping!


Solution

  • drawLine does not conform to the signature of the abstract method in Consumer.

    You created a List of Consumer<Void> objects, so you have to pass in Consumer<Void> objects. The Consumer class, like all functional interfaces, has exactly one abstract method:

    public void accept(T argument)
    

    Your method reference must match that signature. A method’s signature is its return type and its argument types. So, each of your method references must be one of the following:

    • a static method with exactly the same return type and the same arguments
    • a non-static method, with the same return type, which belongs to a type that matches the first argument of the above method, and whose remaining arguments match the remaining arguments of the above method.

    The accept method of Consumer has only one argument, so there are zero “remaining arguments.” Therefore, your method reference must be one of the following:

    • a static method which returns void and which accepts one argument of type Void (since your List requires Consumer<Void> objects)
    • a non-static method belonging to class Void which which returns void and which expects zero arguments

    Obviously, Graphics.drawLine conforms to neither of those. drawLine does return void, but it certainly does not take a Void argument. In fact, it requires four arguments, so it cannot qualify as a Consumer, ever.

    You will have to define your own functional interface. For instance:

    public interface RectangularShapeDrawer {
        void draw(Graphics g, int x1, int y1, int x2, int y2);
    }
    

    Then use that type in your List:

    List<RectangularShapeDrawer> drawers = new ArrayList<>();
    drawers.add(Graphics::drawLine);
    drawers.add(Graphics::drawRect);
    drawers.add(Graphics::drawOval);
    

    In my opinion, since the Graphics.draw* methods are just one line of code each, you are better off writing three separate ActionListeners.