обрабатывать исключения, вызванные сканером ввода

Я пытаюсь сделать программу кодирования/декодирования, и я сталкиваюсь здесь со всеми видами исключений!

проблемы, которые появляются, вызванные несколькими/одними сканерами:

  • InputMismatchException | NumberFormatException (ПОПЫТКА 2)

  • NoSuchElementException (ПОПЫТКА 3)

Прежде чем продолжить, я хотел бы сказать, что это не дубликат, и я просмотрел множество проблем такого рода в StackOverFlow, и ни одна из них мне не помогла. Похожие проблемы, которые я рассматривал: link1 link2

Обратите внимание, что желаемые конечные результаты аналогичны результатам первой попытки, но с более чистой обработкой исключений и закрытыми сканерами.

ПЕРВАЯ ПОПЫТКА

  • Теперь эта программа дает мне желаемые результаты, но это плохое программирование иметь два сканера, и один из них (сканер метода ввода) никогда не закрывается:

    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 вход в режим кодирования! введите последовательность байтов, пожалуйста! non-int прервет ввод! 1 e вход прекращен! 1 закодированный список 1 Это программа для кодирования или декодирования байтов на основе алгоритма RLE ALgorithm (o_O). Варианты: 1: нажмите 1, чтобы войти в режим кодирования 2: нажмите 2, чтобы войти режим декодирования 3: Нажмите 3 для выхода! неверный тип или формат! вход в режим кодирования! введите последовательность байтов, пожалуйста! non-int прервет ввод!

  • ПРИМЕЧАНИЯ:

  • 1. комментирование sc.close() в main вызвало ту же ошибку, что и выше..
  • 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 не имеет шансов появиться, а InputMismatchException обрабатывается и предотвращается блоком else:

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

comment
Эй, в вашей 3-й попытке ваш ввод: -1, -1, е... и затем вы получаете все сообщения, в которых нет такого? Или ваш ввод: -1, -1, e, X? (будучи X каким-то другим входом)   -  person Villat    schedule 10.10.2019
comment
спасибо, сэр, за попытку помочь, но при вводе данных для метода ввода я явно поставил попытку и поймать с ошибкой для обработки InputMismatchException, но это не проблема, это просто завершит ввод в методе ввода, и моя основная проблема заключается в третья попытка при закрытии входного потока, NoSuchElementException catch каким-то образом активируется в основном?   -  person StudentAccount4    schedule 11.10.2019
comment
Я пытаюсь понять символы, которые вы вводите в 3-й попытке, это -1, -1, e... или -1, -1, e, X (будучи X каким-то другим символом)?   -  person Villat    schedule 11.10.2019
comment
сэр, вход имеет тип byte, и он будет принимать только числа для сохранения в байтах, и в случае любой буквы (e или X или что-то еще) ввод будет завершен. поэтому сканер будет принимать только числа, а все остальное приведет к искажению ввода   -  person StudentAccount4    schedule 11.10.2019
comment
после передачи чего-либо, кроме in, входной поток будет завершен, и программа должна работать с этим. такой небольшой пример -1,1,3,x (x равно & $§!%/)= ) завершит ввод независимо от того, является ли это знаком или буквой. поэтому, пока ваш ввод является числом, ввод не будет завершен.   -  person StudentAccount4    schedule 11.10.2019


Ответы (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();
}
person Villat    schedule 11.10.2019
comment
Спасибо чувак!. не могли бы вы снова взять бабло на пост, я добавил кое-что, что я хотел бы обсудить с вами;) - person StudentAccount4; 12.10.2019
comment
Привет, @studentaccount4, лучше обрабатывать все исключения, это дает тебе контроль над кодом. Если мой ответ был полезен, вы можете принять его и проголосовать :) - person Villat; 13.10.2019