我Java通用控制台输入方法的改进方法是什么?

5
使用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;
    }

我收到了一个警告 "类型安全:从Integer到T的未检查转换"。除了使用@SuppressWarnings,还有其他方法可以避免这个警告吗?

有没有更好的实现方法?谢谢。


没有什么问题的警告是很好的,如果你必须消除警告,@SuppressWarnings是最好的解决方案。这意味着你已经检查了代码,并且确定自己在做什么。通过使用Class.cast(),警告只是被移动到某个隐藏的地方。 - irreputable
8个回答

7
你可以使用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<T> 而不是 Class<?>,以确保 Class 实例与类型参数一致。

这就是泛型方法的全部意义(在这种情况下使用)。使用T作为数据类型可以让您将返回类型“连接”到作为第二个参数传递的类。 - f1sh

2
我认为您可能试图过度抽象问题。只是这样做有什么问题吗?
    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原则,“保持简单愚蠢”......

是的,你说得对。我只是对泛型感兴趣,并想着写这个程序,看看在Java中是否可能实现。 - thirdy
除了例外情况,我的想法是强制调用我的方法的人始终处理异常(因为控制台输入容易出错)。这是我想到的一个小好习惯。 - thirdy

2

其他人已经展示了如何使用 Class.cast,但是你应该如何做呢?

我建议使用 readIntreadStringreadFloatreadDouble 方法。此外,我怀疑 Scanner 可能会缓冲,这可能会导致问题。


1

像这样做:

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;
}

0
从这篇文章中阅读, 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;
    }

0
你可以做以下事情:
    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; 
   } 

然而,我强烈建议不要抛出Exception。应当抛出更具体的异常(可以是原始的运行时异常或某个适当的受检查异常)。

最恰当的做法是定义一个特定于应用程序的异常,对吧?顺便说一下,谢谢。 - thirdy

0

您可以通过使用传递给对象的具体类来进行强制转换,从而消除此警告:

    public static <T> T readFromInput(String message, Class<T> c) throws Exception{
        ..
            return c.cast(Integer.valueOf(scanner.nextInt()));
        ..
    }

在这种情况下,我会倾向于实现多个readFromInput方法,并覆盖您想要的类型,例如 public static Float readFromInput(String message, Class c) public static Integer readFromInput(String message, Class c) 等。


0

除了使用@SuppressWarnings (unchecked)注释之外,没有通用的方法可以避免“未经检查的转换”警告。

在特定情况下,您会收到此警告,因为不能保证参数Class<?> c可以转换为T,因为Java的泛型仅在编译时进行检查,并且在运行时可能不进行任何检查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接