0

I am implementing a program which calculate the area and perimeter of a circle and a rectangle. The radius (of circle), width, height (of rectangle) get from user. The problem is: after I type in the radius parameter, the console pop out the message:

Exception in thread "main" java.util.NoSuchElementException at...

Main.java is located in main package, Circle.java and Rectangle.java are located in shapes package.

Main.java:

package main;

import shapes.Circle;
import shapes.Rectangle;

//import java.util.Scanner;

public class Main {
    public static void main(String[] args) {

        Circle cir = new Circle();
        Rectangle rec = new Rectangle();

        cir.printArea();
        cir.printPerimeter();
        rec.printArea();
        rec.printPerimeter();
    }
}

Circle.java:

package shapes;

import java.util.Scanner;

public class Circle {
    final double PI = 3.14;
    double radius;
    double area, perimeter;

    public Circle(double radius) {
        this.radius = radius;
        area = PI*radius*radius;
        perimeter = 2*PI*radius;
    }

    public Circle() {
        System.out.print("radius = ");
        Scanner scan = new Scanner(System.in);
        radius = scan.nextDouble();
        scan.close();
        area = PI*radius*radius;
        perimeter = 2*PI*radius;
    }

    public void printArea() {
        System.out.println("Area of circle = " + area);
    }

    public void printPerimeter() {
        System.out.println("Perimeter of circle = " + perimeter);
    }
}

Rectangle.java:

package shapes;

import java.util.Scanner;

public class Rectangle {
    public double length, width;
    double area, perimeter;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;

        area = length * width;
        perimeter = (length + width) * 2;
    }

    public Rectangle() {
        Scanner scan = new Scanner(System.in);
        System.out.print("width = ");
        width = scan.nextDouble();
        System.out.print("length = ");
        length = scan.nextDouble();
        scan.close();

        area = length * width;
        perimeter = (length + width) * 2;
    }

    public void printArea() {
        System.out.println("Area of rectangle = " + area);
    }

    public void printPerimeter() {
        System.out.println("Perimeter of rectangle = " + perimeter);
    }
}

Why does this happen and how to fix it?

Becker
  • 147
  • 7
  • 1
    You have to give us the *full* stack trace, in your question, formatted as code for readability. – RealSkeptic Jul 03 '22 at 11:57
  • 4
    Closing those scanner will close `System.in` as well. Not a good idea if you plan to read from the standard input again. – Federico klez Culloca Jul 03 '22 at 11:59
  • Does this answer your question? [Scanner is skipping nextLine() after using next() or nextFoo()?](https://stackoverflow.com/questions/13102045/scanner-is-skipping-nextline-after-using-next-or-nextfoo) – tgdavies Jul 03 '22 at 12:00
  • 3
    And by the way, asking for input in the constructor is really bad design. You should ask for those input outside the classes and then pass them what you read as parameters to the constructor. This will allow you to have only one scanner that you can close at the end of your program. – Federico klez Culloca Jul 03 '22 at 12:01
  • 1
    Does this answer your question? [Why is not possible to reopen a closed (standard) stream?](https://stackoverflow.com/questions/33555283/why-is-not-possible-to-reopen-a-closed-standard-stream) – Federico klez Culloca Jul 03 '22 at 12:05
  • 3
    @tgdavies No, that is different problem. Notice that there is no `nextLine()` call in OP code. Here Scanner is trying to read from already closed stream (notice that `System.in` is being closed inside all constructors). Since input stream is closed it means that there can't be more data to read from it. So each attempt to read from closed stream suggest problem with logic of the application. To prevent farther problems (like damaging integrity of DB) JVM attempts to stop such flawed application by throwing *runtime exceptions*, here by throwing `java.util.NoSuchElementException`. – Pshemo Jul 03 '22 at 12:26
  • I get it. Thank you all so much. – Becker Jul 03 '22 at 12:35

2 Answers2

1

you have a few problems..

first, you need to learn how to write more clear code, like: circle, instead of "cir". like Circle circle=new Circle(); second, we usually don't use Scanner inside a constructor try to use inside the method. or create a method for input read. third, don't close the scanner. (most probably this is the cause of the mistake). try to comment your code..

1
  1. Your Scanner should be in the main class and be static you only use one and no need more.
  2. Circle and Rectangle have some base methodes which should be outsorced so use an interface or in this case better a abstract class like Geoform as Superclass.
  3. And don't close the scanner, it is simply not necessary.

Main:

public class Main {
        private static final Scanner scan = new Scanner(System.in);

        private static Circle createCircle(){
            System.out.print("radius = ");
            double radius = scan.nextDouble();
            return new Circle(radius);
        }

        private static Rectangle createRectangle() {
            System.out.print("width = ");
            double width = scan.nextDouble();
            System.out.print("length = ");
            double length = scan.nextDouble();
            
            return new Rectangle(width, length);
        }

        public static void main(String[] args) {

            Circle cir = createCircle();
            Rectangle rec = createRectangle();

            cir.printArea();
            cir.printPerimeter();
            rec.printArea();
            rec.printPerimeter();
        }
    }

Geoform:

public abstract class Geoform {
    final double area;
    final double perimeter;

    public Geoform(double area, double perimeter) {
        this.area = area;
        this.perimeter = perimeter;
    }

    public void printArea() {
        System.out.println("Area = " + area);
    }

    public void printPerimeter() {
        System.out.println("Perimeter = " + perimeter);
    }
}

Circle:

public class Circle extends Geoform{
    public static final double PI = 3.14;
    private final double radius;
    public Circle(double radius) {
        super(PI*radius*radius, 2*PI*radius);
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }
}

Rectangle:

public class Rectangle extends Geoform {
    private final double length, width;
    public Rectangle(double width, double length) {
        super(length * width, (length + width) * 2);
        this.width = width;
        this.length = length;
    }

    public double getLength() {
        return length;
    }

    public double getWidth() {
        return width;
    }
}