Improvement/s to my Java generic console input method?
Using Java Generics, I tried to implement a generic console input method.
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;
}
I'm having a warning "Type safety: Unchecked cast from Integer to T". Aside from @SuppressWarnings, is it possible to avoid this warning?
Are there be开发者_JS百科tter ways to implement my method? Thanks in advance
You can use the Class#cast
method instead, but should leave some comments, because even though cast
does not create a warning, it can throw a ClassCastException at runtime if the cast is not possible.
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;
}
Note that I've changed the method signature slightly - it should be Class<T>
and not Class<?>
to guarantee, that the Class
instance is consistent with the type parameter.
Others have shown how you can do it with Class.cast
, but how should you do it?
I suggest readInt
, readString
, readFloat
and readDouble
methods. Also, I suspect Scanner
may buffer, which could lead you into trouble.
I think you might be trying to over abstract the problem. What's wrong with just doing this?
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();
No cast required and you still have to handle the exception either way........
Remember KISS, "Keep It Simple Stupid"...
Do it like this:
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;
}
Reading from this post, Java generic function: how to return Generic type I got rid of my warning:
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;
}
There's no general way to avoid "Unchecked cast" warning other than using @SuppressWarnings (unchecked)
annotation.
In particular case you get this warning because there's no warranty that parameter Class<?> c
may be cast to T since Java's generics are checked only in compilation and no checks may be done in runtime.
You can do the following:
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;
}
However, I strongly recommend not throwing Exception. Throw a more specific exception (either the original runtime exception or some appropriate checked exception).
You can get rid of the warning by using the concrete class you pass in to cast the object:
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
..
return c.cast(Integer.valueOf(scanner.nextInt()));
..
}
I would tempted in this case to implement multiple readFromInput methods overridden with your desired types, e.g. public static Float readFromInput(String message, Class c) public static Integer readFromInput(String message, Class c) etc.
精彩评论