Как сделать так, чтобы после выброса исключения программа принуждала еще раз ввести значение, пока не будет введено верное?

Возможно кто-то подскажет, как в нижеприведённом коде можно сделать так, чтобы после выброса исключения программа принуждала ещё раз ввести значение, пока не будет введено верное. То есть подобие цикла while, но в консоли должно обязательно выводиться исключение, и затем был бы повторный ввод значения с того момента, где оно было неверное.

Я пытался делать через while внутри try, но тогда либо не срабатывает throw, либо нельзя вводить новое значение, так как код перепрыгивает в catch (что логично).
Рекурсия вызывает метод с начала, то есть если первое значение было верным — его нужно вводить заново. А мне нужно и выводить исключение в консоль, и возвращаться на место, где было неверное значение.
Если это возможно — подскажите как это можно сделать, чтобы не создавать лишние классы исключений.

Код учебный, написанный мною. В нем я учусь работать с исключениями. Заранее спасибо всем за подсказки.

private static void triangleParametersValidityCheck() {
    Scanner scan = new Scanner(System.in);
    try {
        System.out.println("Enter the length of side A:");
        double sideA = scan.nextDouble();
        if (sideA <= 0) {
            throw new ValidValues("Such a triangle does not exist!");
        }
        System.out.println("Enter the length of side B:");
        double sideB = scan.nextDouble();
        if (sideB <= 0) {
            throw new ValidValues("Such a triangle does not exist!");
        }
        System.out.println("Enter the length of side C:");
        double sideC = scan.nextDouble();
        if (sideC <= 0) {
            throw new ValidValues("Such a triangle does not exist!");
        }
        System.out.println("Enter the sine of the angle between the sides: ");
        double sin = scan.nextDouble();
        if (sin <= 0) {
            throw new ValidValues("The sine of the angle cannot be zero or have a negative value!");
        }
        System.out.println("Enter the height of the triangle: ");
        double height = scan.nextDouble();
        if (height <= 0) {
            throw new ValidValues("The height of the triangle must be greater than zero!");
        } else {
            Triangle triangle = new Triangle(sideA, sideB, sideC);
            Triangle triangle2 = new Triangle(sideA, sideB, sin);
            Triangle triangle3 = new Triangle(sideA, height);
            System.out.println("Perimeter of a triangle is " + (triangle.perimeter()));
            System.out.println("Area of a triangle found by Heron's formula is " + (triangle.area()));
            System.out.println("Area of a triangle found by the product of two sides and the angle between them is " +
                    (triangle2.area(sideA, sideB, sin)));
            System.out.println("Area of a triangle found by a base height product is " + (triangle3.area(sideA, height)));
        }
    } catch (ValidValues e) {
        e.printStackTrace();
        System.out.println("Try again!");
    }
}

Ответы (3 шт):

Автор решения: Alexander Chernin

Правильно говорит @Byb и можно обойтись без переменной в while:

while(true) {
    try {
        // Ваш код
        
        break; // Последняя строчка в блоке try выкидывает из цикла
    } catch (ValidValues e) {
        e.printStackTrace();
        System.out.println("Try again!");
    }
}
→ Ссылка
Автор решения: Nowhere Man

Лучше вынести чтение данных в отдельный метод и пока не будет корректный ввод, выхода из этого метода не будет (в данном случае рекурсия отработает корректно), тогда и цикл не понадобится.

Также имеет смысл добавить обработку некорректного ввода, когда сканер выбросит InputMismatchException, и для продолжения работы понадобится "прочитать" неправильно введённое значение, вызвав scan.next().

private static double readDouble(Scanner scan, String prompt, String error) {
    try {
        System.out.println(prompt);
        double result = scan.nextDouble(); // InputMismatchException
        if (result <= 0) {
            throw new ValidValues(error);
        }
        return result;
    } catch (ValidValues | InputMismatchException ex) {
        if (ex instanceof InputMismatchException) {
            System.out.println("Invalid input: " + scan.next());
        }
        ex.printStackTrace();
        System.out.println("Try again!");
        return readDouble(scan, prompt, error);
    }
}

Соответственно, исходный метод triangleParametersValidityCheck значительно улучшится, так как благодаря вынесению общей функциональности в отдельный метод будет устранено дублирование кода, и логика метода triangleParametersValidityCheck станет линейной (без лишних ветвлений):

public static void triangleParametersValidityCheck() {
    Scanner scan = new Scanner(System.in);

    double sideA  = readDouble(scan, "Enter the length of side A:", "Such a triangle does not exist!");
    double sideB  = readDouble(scan, "Enter the length of side B:", "Such a triangle does not exist!");
    double sideC  = readDouble(scan, "Enter the length of side C:", "Such a triangle does not exist!");
    double sin    = readDouble(scan, "Enter the sine of the angle between the sides A and B: ", "The sine of the angle cannot be zero or have a negative value!");
    double height = readDouble(scan, "Enter the height of the triangle: " , "The height of the triangle must be greater than zero!");

    Triangle triangle1 = new Triangle(sideA, sideB, sideC);
    Triangle triangle2 = new Triangle(sideA, sideB, sin);
    Triangle triangle3 = new Triangle(sideA, height);
    System.out.println("Perimeter of the triangle is " + triangle1.perimeter());
    System.out.println("Area of the triangle found by Heron's formula is " + triangle1.area());
    System.out.println("Area of the triangle found by the product of two sides and the angle between them is " + triangle2.area(sideA, sideB, sin));
    System.out.println("Area of the triangle found by a base height product is " + triangle3.area(sideA, height));
}

При необходимости изменить логику проверки, например, чтобы введённые значения были не только больше 0, можно параметризовать метод readDouble, добавив в него функцию-предикат Predicate<Double> / DoublePredicate:

private static double readDouble(Scanner scan, String prompt, String error, DoublePredicate condition) {
    try {
        System.out.println(prompt);
        double result = scan.nextDouble(); // здесь также возможны исключения
        if (!condition.test(result)) { // или condition.negate().test(result)
            throw new ValidValues(error);
        }
        return result;
    } catch (ValidValues | InputMismatchException ex) {
        if (ex instanceof InputMismatchException) {
            System.out.println("Invalid input: " + scan.next());
        }
        ex.printStackTrace();
        System.out.println("Try again!");
        return readDouble(scan, prompt, error);
    }
}

private static double readPositiveDouble(Scanner scan, String prompt, String error) {
    return readDouble(scan, prompt, error, d -> d > 0);
}
→ Ссылка
Автор решения: PavelPavlik

Решил задачу так:

     private static void triangleParametersValidityCheck() {
    Scanner scan = new Scanner(System.in);
    double sideA = 0;
    double sideB = 0;
    double sideC = 0;
    double sin = 0;
    double height = 0;

    while (sideA <= 0) {
        try {
            System.out.println("Enter the length of side A:");
            sideA = scan.nextDouble();
            if (sideA <= 0) {
                throw new ValidValues("Such a triangle does not exist!");
            }
        } catch (ValidValues e) {
            e.printStackTrace();
            System.out.println("Try again!");
        }
    }
    while (sideB <= 0) {
        try {
            System.out.println("Enter the length of side B:");
            sideB = scan.nextDouble();
            if (sideB <= 0) {
                throw new ValidValues("Such a triangle does not exist!");
            }
        } catch (ValidValues e) {
            e.printStackTrace();
            System.out.println("Try again!");
        }
    }
    while (sideC <= 0) {
        try {
            System.out.println("Enter the length of side C:");
            sideC = scan.nextDouble();
            if (sideC <= 0) {
                throw new ValidValues("Such a triangle does not exist!");
            }
        } catch (ValidValues e) {
            e.printStackTrace();
            System.out.println("Try again!");
        }
    }
    while (sin <= 0) {
        try {
            System.out.println("Enter the sine of the angle between the sides: ");
            sin = scan.nextDouble();
            if (sin <= 0) {
                throw new ValidValues("The sine of the angle cannot be zero or have a negative value!");
            }
        } catch (ValidValues e) {
            e.printStackTrace();
            System.out.println("Try again!");
        }
    }
    while (height <= 0) {
        try {
            System.out.println("Enter the height of the triangle: ");
            height = scan.nextDouble();
            if (height <= 0) {
                throw new ValidValues("The height of the triangle must be greater than zero!");
            }
        } catch (ValidValues e) {
            e.printStackTrace();
            System.out.println("Try again!");
        }
    }
    Triangle triangle = new Triangle(sideA, sideB, sideC);
    Triangle triangle2 = new Triangle(sideA, sideB, sin);
    Triangle triangle3 = new Triangle(sideA, height);
    System.out.println("Perimeter of a triangle is " + (triangle.perimeter()));
    System.out.println("Area of a triangle found by Heron's formula is " + (triangle.area()));
    System.out.println("Area of a triangle found by the product of two sides and the angle between them is " +
            (triangle2.area(sideA, sideB, sin)));
    System.out.println("Area of a triangle found by a base height product is " + (triangle3.area(sideA, height)));
}

}

→ Ссылка