Используя Дженерики Java, я пытался реализовать универсальный консольный метод ввода.
public static <T> T readFromInput(String message, Class<?> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
return (T) Integer.valueOf(scanner.nextInt());
if(c == String.class)
return (T) scanner.nextLine();
if(c == Double.class)
return (T) Double.valueOf(scanner.nextDouble());
if(c == Float.class)
return (T) Float.valueOf(scanner.nextFloat());
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
У меня есть предупреждение "Безопасность с точки зрения типов: Неконтролируемый бросок от Целого числа до T". Кроме @SuppressWarnings, действительно ли возможно избежать этого предупреждения?
Там лучшие пути состоят в том, чтобы реализовать мой метод?Заранее спасибо
Вы можете использовать метод Class#cast
вместо этого, но должны оставить некоторые комментарии, потому что хотя cast
не создает предупреждения, он может выбросить ClassCastException во время выполнения, если приведение невозможно.
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
// the next cast to Integer is safe
return c.cast(Integer.valueOf(scanner.nextInt()));
if(c == String.class)
// the next cast to String is safe
return c.cast(scanner.nextLine());
if(c == Double.class)
// the next cast to Double is safe
return c.cast(Double.valueOf(scanner.nextDouble()));
if(c == Float.class)
// the next cast to Float is safe
return c.cast(Float.valueOf(scanner.nextFloat()));
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
Обратите внимание, что я немного изменил сигнатуру метода - она должна быть Class
, а не Class>
, чтобы гарантировать, что экземпляр Class
соответствует параметру типа.
Другие показали, как это можно сделать с помощью Class.cast
, но как это сделать?
Я предлагаю readInt
, readString
, readFloat
и readDouble
методы. Кроме того, я подозреваю, что Сканер
может буферизоваться, что может привести к неприятностям.
Я думаю, вы пытаетесь излишне абстрагироваться от проблемы. Что плохого в том, чтобы просто сделать это?
Scanner scanner = new Scanner(System.in);
System.out.println("Give me a boolean:");
boolean bool = scanner.nextBoolean();
System.out.println("Give me an integer:");
int integer = scanner.nextInt();
Приведение не требуется, и вам все равно придется обрабатывать исключение в любом случае ........
Помните KISS, "Keep It Simple Stupid" ...
Сделайте это так:
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
return c.cast(scanner.nextInt());
if(c == String.class)
return c.cast(scanner.nextLine());
if(c == Double.class)
return c.cast(scanner.nextDouble());
if(c == Float.class)
return c.cast(scanner.nextFloat());
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
Чтение из этого поста, Java generic function: как вернуть Generic type , я избавился от предупреждения:
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
return c.cast(scanner.nextInt());
if(c == String.class)
return c.cast(scanner.nextLine());
if(c == Double.class)
return c.cast(scanner.nextDouble());
if(c == Float.class)
return c.cast(scanner.nextFloat());
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
Не существует общего способа избежать предупреждения "Unchecked cast", кроме использования аннотации @SuppressWarnings (unchecked)
.
В конкретном случае вы получаете это предупреждение, потому что нет гарантии, что параметр Class> c
может быть приведен к T, поскольку дженерики Java проверяются только при компиляции, и никаких проверок не может быть сделано во время выполнения.
Вы можете сделать следующее:
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
return c.cast(scanner.nextInt());
if(c == String.class)
return c.cast(scanner.nextLine());
if(c == Double.class)
return c.cast(scanner.nextDouble());
if(c == Float.class)
return c.cast(scanner.nextFloat());
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
Однако я настоятельно рекомендую не генерировать исключение. Вызвать более конкретное исключение (либо исходное исключение времени выполнения, либо какое-либо подходящее проверенное исключение).
Вы можете избавиться от предупреждения, используя конкретный класс, который вы передаете для приведения объекта:
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
..
return c.cast(Integer.valueOf(scanner.nextInt()));
..
}
В этом случае я бы хотел реализовать несколько методов readFromInput, переопределенных вашими желаемыми типами, например общедоступный статический Float readFromInput (строковое сообщение, класс c) общедоступное статическое целое число readFromInput (строковое сообщение, класс c) и т. д.