处理由输入扫描仪引起的异常

3

我正在尝试编写编码/解码程序,但是我遇到了各种异常!

出现问题的原因是由多个/单个扫描器引起的:

  • InputMismatchException | NumberFormatException(尝试2)

  • NoSuchElementException(尝试3)

在继续之前,我想说明这不是重复的问题,我已经在StackOverFlow上查看了多个类似的问题,但没有真正帮助我解决。

我查看的类似问题:链接1 链接2

请注意,期望的最终结果类似于第一次尝试的结果,但具有更好的清晰的异常处理和关闭的扫描器。

第一次尝试

  • Now this program gives me the desired results but its a bad programming to have two scanners and one of them ( input method scanner ) is never closed:

    public static void main(String[] args) {
    Scanner sc=new Scanner (System.in);
    int choice = 0;
    do {
        System.out.println("This program to encode or decode a byte array " +
                "\n (o_O) Choices are: " +
                "\n 1: Press 1 to enter the encode mode" +
                "\n 2: Press 2 to enter the decode mode" +
                "\n 3: Press 3 to Exit!");
        try {
            //it has to be parseInt because if you used sc.nextInt() the program will go nuts even with try catch.
            choice=Integer.parseInt(sc.next());
            //choice=sc.nextInt();
            /*Question: why when i use this with the existing try catch i the program work for ever but when i use Integer.parseInt(sc.nextLine())
             * the program would normally ask for another value?
             */
        } catch (InputMismatchException | NumberFormatException e) {
            System.out.println("invalid type or format!");
        } catch (NoSuchElementException e) {
            System.out.println("no such");
            //break; if i uncomment this the programm will work For Ever
        }
        switch(choice){
    
        case 1 :
            System.out.println("entering the encode mode!");
            countAndEncode( input() );
            break;
        case 2 :
            countAndDecode( input() );
            break;
        case 3 :
            System.out.println("exiting...");
            break;
        default :
            System.out.println("please enter a valid option and valid format!");
        }
    
    } while (choice!=3);
    sc.close();
     }
    
     public static byte [] input() {
    //arrayList because we dont know the size of the array its like StringBuilder
    //ArrayList<Byte> inArray = new ArrayList<Byte>(); 
    //according to StackOverflow using ArrayList to store bytes is inefficient
    Scanner inScanner=new Scanner (System.in);
    
    ByteArrayOutputStream inArray= new ByteArrayOutputStream();
    
    System.out.println("enter a sequence of ints please! ");
    System.out.println("non-int will terminate the input!");
    
    while (inScanner.hasNext()) {
        byte i;
        try {
            i = inScanner.nextByte();
            inArray.write(i);
        } catch (InputMismatchException e) {
            System.out.println("input terminated!");
            break;
        }
    }
    //System.out.println(Arrays.toString(inArray.toByteArray()));
    //inScanner.close();
    return inArray.toByteArray();
     }
    

第一次尝试的输出结果:

This is a program to encode or decode bytes based on RLE ALgorithm
(o_O) Choices are: 
 1: Press 1 to enter the encode mode
 2: Press 2 to enter the decode mode
 3: Press 3 to Exit!
 1
 entering the encode mode!
 enter a sequence of bytes please! 
 non-int will terminate the input!
 1
 1
 3
 e
 input terminated!
 [1, 1, 3]
 the encoded list is [-1, 1, 2, 3]
 This is a program to encode or decode bytes based on RLE ALgorithm
 (o_O) Choices are: 
 1: Press 1 to enter the encode mode
 2: Press 2 to enter the decode mode
 3: Press 3 to Exit!
 At it goes forever without errors.

第二次尝试

在有位同仁建议我查看这个问题的链接后,我做了以下操作:

现在我没有关闭输入扫描器,并给了输入方法一个扫描器作为参数:

public static void main(String[] args) {
    Scanner sc=new Scanner (System.in);
    int choice = 0;
    do {
        System.out.println("This is a program to encode or decode bytes based on RLE ALgorithm" +
                "\n (o_O) Choices are: " +
                "\n 1: Press 1 to enter the encode mode" +
                "\n 2: Press 2 to enter the decode mode" +
                "\n 3: Press 3 to Exit!");
        try {
            //it has to be parseInt because if you used sc.nextInt() the program will go nuts even with try catch.
            choice=Integer.parseInt(sc.next());
            //choice=sc.nextInt();
            /*Question: why when i use this with the existing try catch i the program work for ever but when i use Integer.parseInt(sc.nextLine())
             * the program would normally ask for another value?
             */
        } catch (InputMismatchException | NumberFormatException e) {
            System.out.println("invalid type or format!");
        } catch (NoSuchElementException e) {
            System.out.println("no such");//TODO SOLVE IT PLEASE ITS DRIVING ME CRAZYYYYYYYYYYY!!!!!!!
            break;
        }
        switch(choice){

        case 1 :
            System.out.println("entering the encode mode!");
            countAndEncode( input(sc) );
            break;
        case 2 :
            //countAndDecode( input(sc) );
            break;
        case 3 :
            System.out.println("exiting...");
            break;
        default :
            System.out.println("please enter a valid option and valid format!");
        }

    } while (choice!=3);
    sc.close();
}
/**
 * with this method user will be able to give the desired sequence of bytes. 
 * @return a byte array to be encoded.
 */
public static byte [] input(Scanner inScanner) {
    //arrayList because we dont know the size of the array its like StringBuilder
    //ArrayList<Byte> inArray = new ArrayList<Byte>(); 
    //according to StackOverflow using ArrayList to store bytes is inefficient
    //Scanner   inScanner=new Scanner (System.in);

    ByteArrayOutputStream inArray= new ByteArrayOutputStream();

    System.out.println("enter a sequence of bytes please! ");
    System.out.println("non-int will terminate the input!");

    while (inScanner.hasNext()) {//TODO THIS MIGHT BE THE REASON FOR THE above "SUCH"
        byte i;
        try {
            i = inScanner.nextByte();   
            inArray.write(i);   
        } catch (InputMismatchException e) {
            System.out.println("input terminated!");
            break;
        }
    }
    System.out.println(Arrays.toString(inArray.toByteArray()));
    //inScanner.close();  dont close it because it cant be re-opened
    return inArray.toByteArray();
}

这样做根本没有给我想要的结果:
- 在选择一个字节进行编码并接收编码后的字节后,我将永远陷入编码模式中,而且InputMismatchException | NumberFormatException子句将被激活,所以我无法有机会选择新输入! - 这是一个基于RLE算法对字节进行编码或解码的程序(o_O) 选项如下: 1. 按1进入编码模式 2. 按2进入解码模式 3. 按3退出! 1 进入编码模式! 请输入一系列字节! 非int类型将终止输入! 1 e 输入终止! 1 编码后的列表为1 这是一个基于RLE算法对字节进行编码或解码的程序(o_O) 选项如下: 1. 按1进入编码模式 2. 按2进入解码模式 3. 按3退出! 类型或格式无效! 进入编码模式! 请输入一系列字节! 非int类型将终止输入!
注意事项:
- 1.在主函数中注释掉sc.close()与上述错误完全相同。 - 2.将扫描器移动到主函数之上并将其声明为全局静态变量,结果与上述失败的结果完全相同。
第三次尝试:
现在我将两个扫描器都关闭了,这导致在主函数中激活了NoSuchElementException。看一下:
public static void main(String[] args) {
    Scanner sc=new Scanner (System.in);
    int choice = 0;
    do {
        System.out.println("This is a program to encode or decode bytes based on RLE ALgorithm" +
                "\n (o_O) Choices are: " +
                "\n 1: Press 1 to enter the encode mode" +
                "\n 2: Press 2 to enter the decode mode" +
                "\n 3: Press 3 to Exit!");
        try {
            //it has to be parseInt because if you used sc.nextInt() the program will go nuts even with try catch.
            choice=Integer.parseInt(sc.next());
            //choice=sc.nextInt();
            /*Question: why when i use this with the existing try catch i the program work for ever but when i use Integer.parseInt(sc.nextLine())
             * the program would normally ask for another value?
             */
        } catch (InputMismatchException | NumberFormatException e) {
            System.out.println("invalid type or format!");
        } catch (NoSuchElementException e) {
            System.out.println("no such");//TODO SOLVE IT PLEASE ITS DRIVING ME CRAZYYYYYYYYYYY!!!!!!!
            break;
        }
        switch(choice){

        case 1 :
            System.out.println("entering the encode mode!");
            countAndEncode( input() );
            break;
        case 2 :
            //countAndDecode( input() );
            break;
        case 3 :
            System.out.println("exiting...");
            break;
        default :
            System.out.println("please enter a valid option and valid format!");
        }

    } while (choice!=3);
    sc.close();
}
/**
 * with this method user will be able to give the desired sequence of bytes. 
 * @return a byte array to be encoded.
 * @throws IOException 
 */
public static byte [] input() {
    //arrayList because we dont know the size of the array its like StringBuilder
    //ArrayList<Byte> inArray = new ArrayList<Byte>(); 
    //according to StackOverflow using ArrayList to store bytes is inefficient
    Scanner inScanner=new Scanner (System.in);

    ByteArrayOutputStream inArray= new ByteArrayOutputStream();

    System.out.println("enter a sequence of bytes please! ");
    System.out.println("non-int will terminate the input!");

    while (inScanner.hasNext()) {//TODO THIS MIGHT BE THE REASON FOR THE above "SUCH"
        byte i;
        try {
            i = inScanner.nextByte();   
            inArray.write(i);   
        } catch (InputMismatchException e) {
            System.out.println("input terminated!");
            break;
        }
    }
    System.out.println(Arrays.toString(inArray.toByteArray()));
    inScanner.close(); 
    return inArray.toByteArray();
}

在这个尝试中,至少我知道什么导致了NoSuchElementException的出现,我认为是因为关闭一个扫描器将会关闭整个代码的输入流。(如果我说错了,请纠正我!)
第三次尝试的输出结果是:
This is a program to encode or decode bytes based on RLE ALgorithm
(o_O) Choices are: 
 1: Press 1 to enter the encode mode
 2: Press 2 to enter the decode mode
 3: Press 3 to Exit!
 1
 entering the encode mode!
 enter a sequence of bytes please! 
 non-int will terminate the input!
-1
-1
 e
 input terminated!
 [-1, -1]
 the encoded list is [-1, -1, -1, -1]
 This is a program to encode or decode bytes based on RLE ALgorithm
 (o_O) Choices are: 
 1: Press 1 to enter the encode mode
 2: Press 2 to enter the decode mode
 3: Press 3 to Exit!
no such
@Villat的解决方案

首先,非常感谢您的帮助和投入时间和精力。

现在,我有一个关于这些行的小问题:

 if(sc.hasNextInt()) choice=sc.nextInt();
            else {
                sc.next();
                continue;
            }
            error = false;
  • 那么让我看看,如果我理解正确的话,这些行作为一种预防措施发挥作用,如果我错了,请纠正我!以防止异常弹出。

那么是否只写以下内容就足够了,抛弃try-catch块,因为NoSuchElementException没有机会出现,而且通过else块处理并防止了InputMismatchException

             while (error){
             if(sc.hasNextInt()) choice=sc.nextInt();
             else {
                 sc.next();
                 continue;
             }
             error = false;
             }

如果我想通过try-catch块来处理这个错误,你认为这样写是否干净、免疫异常:(放弃NumberFormatException)。

- 那么展示你回答中的Handle variant,应该是这样的对吧?

                while (error){
                try {
                    choice=sc.nextInt();
                    error = false;                
                } catch (InputMismatchException /*| NumberFormatException*/ e) {
                    error = false;
                    //System.out.println("invalid type or format!");    
                    sc.next();
                    continue;
                }
            }

嘿,在你的第三次尝试中,你的输入是:-1,-1,e...然后你得到了所有包括“没有这样”的消息吗?或者你的输入是:-1,-1,e,X?(其中X是其他输入) - Villat
感谢您的帮助,但是当我向输入方法提供输入时,我明确地使用了try和catch来处理“InputMismatchException”,但这不是问题所在。这只会终止输入方法,我的主要问题是在第三次尝试关闭输入流时,“NoSuchElementException”捕获在主函数中以某种方式被激活了? - StudentAccount4
我正在尝试理解您在第三次尝试中输入的字符,它们是-1,-1,e...还是-1,-1,e,X(其中X是另一个字符)? - Villat
先生,输入的类型是字节型,它只接受数字以保存在字节中。如果输入中包含任何字母(例如 e 或 X),将导致输入终止。因此,扫描器只接受数字,其他任何内容都会导致输入被终止。 - StudentAccount4
只要输入流中不是整数,程序就会终止并以此为基础运行。因此,例如输入-1、1、3、x(其中x为& $§""!"%/)=),无论其符号或字母如何,都将终止输入。只要您的输入是数字,输入就不会被终止。 - StudentAccount4
1个回答

1
我对你的代码进行了一些更改(并删除了注释以使其更易读)。基本上,现在我只使用一个Scanner,并且在出现sc.nextInt()之前不会进入选项。
public static void main(String[] args){
    Scanner sc=new Scanner (System.in);
    int choice = 0;
    do {
        System.out.println("This is a program to encode or decode bytes based on RLE ALgorithm" +
                "\n (o_O) Choices are: " +
                "\n 1: Press 1 to enter the encode mode" +
                "\n 2: Press 2 to enter the decode mode" +
                "\n 3: Press 3 to Exit!");
        boolean error = true;
        while (error){
            try {
                if(sc.hasNextInt()) choice=sc.nextInt();
                else {
                    sc.next();
                    continue;
                }
                error = false;
            } catch (InputMismatchException | NumberFormatException e) {
                System.out.println("invalid type or format!");
            } catch (NoSuchElementException e) {
                System.out.println("no such");
            }
        }
        switch(choice){

            case 1 :
                System.out.println("entering the encode mode!");
                System.out.println(input(sc));
                break;
            case 2 :
                //countAndDecode(input(sc));
                break;
            case 3 :
                System.out.println("exiting...");
                break;
            default :
                System.out.println("please enter a valid option and valid format!");
        }

    } while (choice!=3);
    sc.close();
}

输入法:

public static byte [] input(Scanner sc) {
    ByteArrayOutputStream inArray= new ByteArrayOutputStream();

    System.out.println("enter a sequence of bytes please! ");
    System.out.println("non-int will terminate the input!");

    while (sc.hasNext()) {
        byte i;
        try {
            i = sc.nextByte();
            inArray.write(i);
        } catch (InputMismatchException e) {
            System.out.println("input terminated!");
            break;
        }
    }
    System.out.println(Arrays.toString(inArray.toByteArray()));
    return inArray.toByteArray();
}

谢谢你!你能再看一下帖子吗?我添加了一些想和你讨论的观点 ;) - StudentAccount4
嘿@studentaccount4,最好处理所有的异常,这样可以控制代码。如果我的回答有帮助,请接受并投票 :) - Villat

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