Improvement/s to my Java generic console input met

2019-02-17 17:45发布

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 better ways to implement my method? Thanks in advance

8条回答
Summer. ? 凉城
2楼-- · 2019-02-17 17:53

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).

查看更多
一夜七次
3楼-- · 2019-02-17 17:56

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.

查看更多
劳资没心,怎么记你
4楼-- · 2019-02-17 18:00

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"...

查看更多
放我归山
5楼-- · 2019-02-17 18:01

You can use the Class#castmethod 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.

查看更多
孤傲高冷的网名
6楼-- · 2019-02-17 18:02

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.

查看更多
混吃等死
7楼-- · 2019-02-17 18:07

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;
}
查看更多
登录 后发表回答