Ошибка при считывании типа double сканером

import java.util.Scanner;
    
public class TaxiCost {
    public static void main(String[] args) {
        final double FARE_PER_KM = 8; 
        
        double startIndicationOdo, endIndicationOdo, way, tax; 
        
        Scanner input = new Scanner(System.in);
        
        System.out.print("Введите начальные показания одометра: ");
        startIndicationOdo = input.nextDouble();
        
        System.out.print("Введите конечные показания одометра: ");
        endIndicationOdo = input.nextDouble();
        
        way = (int )((endIndicationOdo - startIndicationOdo) * 100 + 0.5) / 100.0;
        
        tax = (int )((way * FARE_PER_KM) * 100 + 0.5) / 100.0;
        
        System.out.println("Вы проехали " + way + ". Из расчета 8 руб. за км,");
        System.out.println("стоимость проезда равна " + tax + " руб.");
    }
}

Компиляцию успешно проходит. Но когда в консоли cmd(win10) ввести число типа double, выдает ошибку:

Exception in thread "main" java.util.InputMismatchException

А если ввести целое число, ошибку не выдает.

Почему так происходит?


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

Автор решения: Alex Rudenko

Дело в том, что при создании Scanner используется локаль по умолчанию Locale.getDefault(), и метод input.nextDouble() использует эти региональные настройки (для русской локали, как и для многих других европейских: немецкой, французской, итальянской и др., используется десятичная запятая вместо десятичной точки).

Существует несколько способов изменения локали:

  • задать системные свойства при запуске: java -Duser.language=ru -Duser.region=RU
  • аналогично вызвать Locale.setDefault(new Locale("ru", "RU")); перед созданием сканера
  • после создания сканера можно использовать метод input.useLocale(); (текущую локаль сканера возвращает метод Scanner::locale)

Альтернативный вариант -- всегда использовать один и тот же разделитель. К примеру, метод Double.parseDouble всегда использует десятичную точку независимо от локали:

String myDouble = input.nextLine(); 
double d = Double.parseDouble(myDouble);

Тогда может понадобиться костыль в виде принудительной замены десятичной запятой на десятичную точку (например, используя String::replace/replaceAll).

→ Ссылка