Domanda I miei errori

Stato
Discussione chiusa ad ulteriori risposte.

KGLion

Utente Bronze
12 Ottobre 2014
21
5
0
43
Ultima modifica:
Sono alle prime armi su Java(non ho mai programmato)quindi mi scuso per i prossimi errori madornali che vedrete.Sto cercando di creare un Menu:
il mio intento è di far scegliere all'utente appunto delle specifiche scelte .Se l'utente scrive un numero che va da 1 a 3,si vedrà il messaggio "Finale",in caso contrario ripartirà il loop.Se l'utente digiterà 'q',il codice si bloccherà.
Il problema è che quando riparte il loop,invece che farmi lasciare la possibilità di scrivere un numero (o lettera),visualizza tipo per 3/4 volte di fila il menu.Cosa sbaglio?
public class Menu {


Codice:
public static void main (String args [] )
   throws java.io.IOException {
     char choice,quite='q'; 
   
pen :   while (true){ 
     System.out.println("Menu :");
     System.out.println("N.1 Object");
     System.out.println("N.2 Object");
     System.out.println("N.3 Object");
     System.out.println("Press 'q' to quit");
     System.out.println(" ");
   
     choice=(char) System.in.read();
   
     
     if (choice == 'q' ) break;
     if (choice < '1' || choice > '3'){
System.out.println("Choose between 1 and 3");
     continue pen;
}
     System.out.println("Finale");break;
           }
     }
  }

Ho intitolato il thread "i miei errori" perchè in futuro m'imbatterò sicuramente in altri "muri":
 
Questo programmino ha diversi problemi... E sì, sono riconducibili a un principiante che sta imparando, ma molti altri sono particolari. In precedenza hai usato C/C++? Perché non segui lo stile di guida del Java con String args [] o pen :.
Già l'utilizzo di etichette è sconsigliato in C/C++ (quando non si deve uscire da cicli complicati o in modo da aumentare la leggibilità del codice). Nel tuo caso il codice risulta più difficile da leggere e il flusso meno chiaro, pensa a come poter implementare il controllo nel while().

Il problema è che usi la classe InputStream direttamente con System.in.read(). Il metodo read() legge un solo byte e ritorna un intero (e in questo caso la conversione che fai per poi confrontare sempre tra interi mi sembra inopportuna). Di fatto, però, quando nella console inserisci il numero e premi Invio, vengono letti:
  • Il byte effettivo del numero
  • Il byte del tasto Invio (carattere ASCII 13)
  • Il byte del "ritorno a capo" o "nuova linea" (carattere ASCII 10)
Per un corretto utilizzo dovresti usare una versione bufferizzata o tramite token. Due esempi sono:
Codice:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
choice = Integer.parseInt(in.readLine())
Codice:
import java.util.Scanner;
/* ... */
Scanner sc = new Scanner(System.in);
choice = sc.nextInt();
 
  • Mi piace
Reazioni: KGLion
Questo programmino ha diversi problemi... E sì, sono riconducibili a un principiante che sta imparando, ma molti altri sono particolari. In precedenza hai usato C/C++? Perché non segui lo stile di guida del Java con String args [] o pen :.
Già l'utilizzo di etichette è sconsigliato in C/C++ (quando non si deve uscire da cicli complicati o in modo da aumentare la leggibilità del codice). Nel tuo caso il codice risulta più difficile da leggere e il flusso meno chiaro, pensa a come poter implementare il controllo nel while().

Il problema è che usi la classe InputStream direttamente con System.in.read(). Il metodo read() legge un solo byte e ritorna un intero (e in questo caso la conversione che fai per poi confrontare sempre tra interi mi sembra inopportuna). Di fatto, però, quando nella console inserisci il numero e premi Invio, vengono letti:
  • Il byte effettivo del numero
  • Il byte del tasto Invio (carattere ASCII 13)
  • Il byte del "ritorno a capo" o "nuova linea" (carattere ASCII 10)
Per un corretto utilizzo dovresti usare una versione bufferizzata o tramite token. Due esempi sono:
Codice:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
choice = Integer.parseInt(in.readLine())
Codice:
import java.util.Scanner;
/* ... */
Scanner sc = new Scanner(System.in);
choice = sc.nextInt();
Purtroppo sono ancora troppo agli inizi per comprendere tutto ciò che hai scritto,non ho mai usato c/c++,ne qualsiasi linguaggio di programmazione,mi sto affacciando a questo mondo con il libro "Java:A Beginner Guide Sixth Edition - by Herbert Schildt",ho anche preso dalla biblioteca il libro di Claudio De Sio Cesari "manuale di java 8" ma non lo trovo chiaro come il primo che ho citato.Guardo anche video tutorial ma sembra che ognuno usa differenti comandi per fare una cosa e questo mi crea grossa confusione....Quindi il "System.in.read" devo evitarlo.
Il libro che sto leggendo riporta questa soluzione:
Codice:
class Help3 {
public static void main(String args[])
throws java.io.IOException {
char choice, ignore;
for(;;) {
do {
System.out.println("Help on:");
System.out.println(" 1. if");
System.out.println(" 2. switch");
System.out.println(" 3. for");
System.out.println(" 4. while");
System.out.println(" 5. do-while");
System.out.println(" 6. break");
System.out.println(" 7. continue\n");
System.out.print("Choose one (q to quit): ");
choice = (char) System.in.read();
do {
ignore = (char) System.in.read();
} while(ignore != '\n');
} while( choice < '1' | choice > '7' & choice != 'q');
if(choice == 'q') break;
System.out.println("\n");
switch(choice) {
case '1':
System.out.println("The if:\n");
System.out.println("if(condition) statement;");
System.out.println("else statement;");
break;
case '2':
System.out.println("The switch:\n");
System.out.println("switch(expression) {");
System.out.println(" case constant:");
System.out.println(" statement sequence");
System.out.println(" break;");
System.out.println(" // ...");
System.out.println("}");
break;
case '3':
System.out.println("The for:\n");
System.out.print("for(init; condition; iteration)");
System.out.println(" statement;");
break;
case '4':
System.out.println("The while:\n");
System.out.println("while(condition) statement;");
break;
case '5':
System.out.println("The do-while:\n");
System.out.println("do {");
System.out.println(" statement;");
System.out.println("} while (condition);");
break;
case '6':
System.out.println("The break:\n");
System.out.println("break; or break label;");
break;
case '7':
System.out.println("The continue:\n");
System.out.println("continue; or continue label;");
break;
}
System.out.println();
}
}
}
 
Ok, quindi non ha altre esperienze in tal senso. Java, per quanto sia un linguaggio ad alto livello (e quindi più vicino a noi che alla macchina), potrebbe essere ostico, ma ovviamente non impossibile se ti ispira di più come primo linguaggio.

La soluzione proposta dal libro affronta il (problematico) input di un carattere leggendo due volte:
Codice:
choice = (char)System.in.read();

do {
    ignore = (char) System.in.read();
}  while(ignore != '\n');
Ed eliminando tutti i successivi byte (o vedili come caratteri) dopo il primo (che è già stato salvato in choice). Questo finché non incontra il carattere di "ritorno a capo", ovvero dopo la pressione del tasto Invio.

Una soluzione diversa può essere l'utilizzo dello Scanner di cui parlavo prima:
Codice:
Scanner sc = new Scanner(System.in);
/* codice */
choice = sc.next().charAt(0);
Cosa stiamo facendo qui? Con il metodo next() leggiamo tutta la riga inserita dall'utente come stringa (tipo String) e con il metodo charAt(0) prendiamo solo il primo carattere di questa stringa (tipo char) (e lo salviamo in choice).

Avrai notato che stai usando un ciclo infinito:
Codice:
for(;;) { ... }

while(true) { ... }
Può essere una soluzione valida, alla fine fai un solo controllo e nel caso esci con l'istruzione break. Un'altra soluzione è di lasciare questo compito al ciclo stesso, tipo con:
Codice:
do { ... } while ((choice >= '1' || choice <= '7') && choice != 'q')

Visto che il problema risiedeva nell'errore di lettura da console (terminale/shell), ora ho solo elencato un paio di metodi alternativi per risolvere il problema, niente di cui preoccuparsi se hai capito l'errore. ;)

Codice:
import java.util.Scanner;

class Help3 {
    public static void main(String[] args) throws java.io.IOException {
        char choice = '0';
        Scanner sc = new Scanner(System.in);

        do {
            System.out.println("Help on:");
            System.out.println(" 1. if");
            System.out.println(" 2. switch");
            System.out.println(" 3. for");
            System.out.println(" 4. while");
            System.out.println(" 5. do-while");
            System.out.println(" 6. break");
            System.out.println(" 7. continue\n");
            System.out.print("Choose one (q to quit): ");

            choice = sc.next().charAt(0);

            System.out.println();

            switch(choice) {
                case '1':
                System.out.println("The if:\n");
                System.out.println("if(condition) statement;");
                System.out.println("else statement;");
                break;

                case '2':
                System.out.println("The switch:\n");
                System.out.println("switch(expression) {");
                System.out.println(" case constant:");
                System.out.println(" statement sequence");
                System.out.println(" break;");
                System.out.println(" // ...");
                System.out.println("}");
                break;

                case '3':
                System.out.println("The for:\n");
                System.out.print("for(init; condition; iteration)");
                System.out.println(" statement;");
                break;

                case '4':
                System.out.println("The while:\n");
                System.out.println("while(condition) statement;");
                break;

                case '5':
                System.out.println("The do-while:\n");
                System.out.println("do {");
                System.out.println(" statement;");
                System.out.println("} while (condition);");
                break;

                case '6':
                System.out.println("The break:\n");
                System.out.println("break; or break label;");
                break;

                case '7':
                System.out.println("The continue:\n");
                System.out.println("continue; or continue label;");
                break;
            }

        } while ((choice >= '1' || choice <= '7') && choice != 'q');
    }
}
 
  • Mi piace
Reazioni: KGLion
Ok, quindi non ha altre esperienze in tal senso. Java, per quanto sia un linguaggio ad alto livello (e quindi più vicino a noi che alla macchina), potrebbe essere ostico, ma ovviamente non impossibile se ti ispira di più come primo linguaggio.

La soluzione proposta dal libro affronta il (problematico) input di un carattere leggendo due volte:
Codice:
choice = (char)System.in.read();

do {
    ignore = (char) System.in.read();
}  while(ignore != '\n');
Ed eliminando tutti i successivi byte (o vedili come caratteri) dopo il primo (che è già stato salvato in choice). Questo finché non incontra il carattere di "ritorno a capo", ovvero dopo la pressione del tasto Invio.

Una soluzione diversa può essere l'utilizzo dello Scanner di cui parlavo prima:
Codice:
Scanner sc = new Scanner(System.in);
/* codice */
choice = sc.next().charAt(0);
Cosa stiamo facendo qui? Con il metodo next() leggiamo tutta la riga inserita dall'utente come stringa (tipo String) e con il metodo charAt(0) prendiamo solo il primo carattere di questa stringa (tipo char) (e lo salviamo in choice).

Avrai notato che stai usando un ciclo infinito:
Codice:
for(;;) { ... }

while(true) { ... }
Può essere una soluzione valida, alla fine fai un solo controllo e nel caso esci con l'istruzione break. Un'altra soluzione è di lasciare questo compito al ciclo stesso, tipo con:
Codice:
do { ... } while ((choice >= '1' || choice <= '7') && choice != 'q')

Visto che il problema risiedeva nell'errore di lettura da console (terminale/shell), ora ho solo elencato un paio di metodi alternativi per risolvere il problema, niente di cui preoccuparsi se hai capito l'errore. ;)

Codice:
import java.util.Scanner;

class Help3 {
    public static void main(String[] args) throws java.io.IOException {
        char choice = '0';
        Scanner sc = new Scanner(System.in);

        do {
            System.out.println("Help on:");
            System.out.println(" 1. if");
            System.out.println(" 2. switch");
            System.out.println(" 3. for");
            System.out.println(" 4. while");
            System.out.println(" 5. do-while");
            System.out.println(" 6. break");
            System.out.println(" 7. continue\n");
            System.out.print("Choose one (q to quit): ");

            choice = sc.next().charAt(0);

            System.out.println();

            switch(choice) {
                case '1':
                System.out.println("The if:\n");
                System.out.println("if(condition) statement;");
                System.out.println("else statement;");
                break;

                case '2':
                System.out.println("The switch:\n");
                System.out.println("switch(expression) {");
                System.out.println(" case constant:");
                System.out.println(" statement sequence");
                System.out.println(" break;");
                System.out.println(" // ...");
                System.out.println("}");
                break;

                case '3':
                System.out.println("The for:\n");
                System.out.print("for(init; condition; iteration)");
                System.out.println(" statement;");
                break;

                case '4':
                System.out.println("The while:\n");
                System.out.println("while(condition) statement;");
                break;

                case '5':
                System.out.println("The do-while:\n");
                System.out.println("do {");
                System.out.println(" statement;");
                System.out.println("} while (condition);");
                break;

                case '6':
                System.out.println("The break:\n");
                System.out.println("break; or break label;");
                break;

                case '7':
                System.out.println("The continue:\n");
                System.out.println("continue; or continue label;");
                break;
            }

        } while ((choice >= '1' || choice <= '7') && choice != 'q');
    }
}
Cavolo,mi hai illuminato!!!Ora ho capito!Grzie mille
Ora però mi viene il dubbio se il libro he sto leggendo sia "buono",potevano benissimo utilizzare lo Scanner....
Domanda probabilmente stupida,ma: "
do { ... } while ((choice >= '1' || choice <= '7') && choice != 'q')" non può essere scritto cosi' "
do { ... } while (choice >= '1' || choice <= '7' || choice != 'q')?
Si,anche altri mi hanno detto che java non è proprio idoneo per iniziare,ma mi attira
 
Per quanto riguarda il libro sembra essere il piu' acquistato su Amazon, suppongo che sia buono. Leggendo alcuni commenti pare che abbia un approccio molto graduale alle nozioni, quindi e' probabile che indrodurra' lo Scanner o altri metodi (bufferizzati) di input piu' avanti.
Certo, personalmente utilizzerei un approcio diverso, ma vengo anche da un libro diverso e difficile per chi sta imparando un linguaggio per la sua prima volta.

Ecco, gia' nel mio codice c'e' un errore subdolo. :p Andando di fretta non ho fatto caso ma per controllare in un range di numeri su usa l'operatore AND (&&) quindi avrei potuto (o dovuto) scrivere:
Codice:
do { ... } while (choice >= '1' && choice <= '7' && choice != 'q')

Nel tuo caso non funziona perche' con gli OR la condizione viene interpretata fino alla prima condizione valida:
Codice:
choice = '0'

WHILE (choice >= '1' || choice <= '7' || choice != 'q')
  -> WHILE (choice >= '1') FALSO
       -> WHILE (choice <= '7') VERO (continua)

choice = '5'

WHILE (choice >= '1' || choice <= '7' || choice != 'q')
  -> WHILE (choice >= '1') VERO (continua)

choice = 'q'

WHILE (choice >= '1' || choice <= '7' || choice != 'q')
  -> WHILE (choice >= '1') VERO (continua)
Anche perche' la lettera q e' piu' grande di qualsiasi numero per via della loro posizione nella tabella ASCII (e in generale tutte le lettere dell'alfabeto). In tipo intero (int) vale 113, quindi e' piu' grande di 1, quindi il ciclo inizia di nuovo senza controllare le altre condizioni perche' basta che una sia vera.

Se poi riguardi attentamente la logica della condizione ti accorgi che e' errata. In generale quando devi controllare anche con != probabilmente ci va un AND logico.
 
  • Mi piace
Reazioni: KGLion
Per quanto riguarda il libro sembra essere il piu' acquistato su Amazon, suppongo che sia buono. Leggendo alcuni commenti pare che abbia un approccio molto graduale alle nozioni, quindi e' probabile che indrodurra' lo Scanner o altri metodi (bufferizzati) di input piu' avanti.
Certo, personalmente utilizzerei un approcio diverso, ma vengo anche da un libro diverso e difficile per chi sta imparando un linguaggio per la sua prima volta.

Ecco, gia' nel mio codice c'e' un errore subdolo. :p Andando di fretta non ho fatto caso ma per controllare in un range di numeri su usa l'operatore AND (&&) quindi avrei potuto (o dovuto) scrivere:
Codice:
do { ... } while (choice >= '1' && choice <= '7' && choice != 'q')

Nel tuo caso non funziona perche' con gli OR la condizione viene interpretata fino alla prima condizione valida:
Codice:
choice = '0'

WHILE (choice >= '1' || choice <= '7' || choice != 'q')
  -> WHILE (choice >= '1') FALSO
       -> WHILE (choice <= '7') VERO (continua)

choice = '5'

WHILE (choice >= '1' || choice <= '7' || choice != 'q')
  -> WHILE (choice >= '1') VERO (continua)

choice = 'q'

WHILE (choice >= '1' || choice <= '7' || choice != 'q')
  -> WHILE (choice >= '1') VERO (continua)
Anche perche' la lettera q e' piu' grande di qualsiasi numero per via della loro posizione nella tabella ASCII (e in generale tutte le lettere dell'alfabeto). In tipo intero (int) vale 113, quindi e' piu' grande di 1, quindi il ciclo inizia di nuovo senza controllare le altre condizioni perche' basta che una sia vera.

Se poi riguardi attentamente la logica della condizione ti accorgi che e' errata. In generale quando devi controllare anche con != probabilmente ci va un AND logico.
Che dire,dovresti aprire un canale youtube e fare tutorial!!
Ora finalmente sto proseguendo col libro.In futuro riposterò sicuramente.
 
Grazie, mi fa piacere che tu sia riuscito a capire gli errori. ;)
Io sono ancora in fase di studio, sono ancora un principiante. Lascio ad altri più esperti e navigati la creazione di tutorial, guide o contenuti, purtroppo spesso vengono sempre trattati i pochi argomenti base e anche nel modo sbagliato. :p

E per quanto riguarda i prossimi problemi apri un nuovo thread per ognuno, su Inforge funziona così. ;)
Ogni volta che il problema viene risolto puoi chiudere te la discussione, ne hai i permessi.
 
Grazie, mi fa piacere che tu sia riuscito a capire gli errori. ;)
Io sono ancora in fase di studio, sono ancora un principiante. Lascio ad altri più esperti e navigati la creazione di tutorial, guide o contenuti, purtroppo spesso vengono sempre trattati i pochi argomenti base e anche nel modo sbagliato. :p

E per quanto riguarda i prossimi problemi apri un nuovo thread per ognuno, su Inforge funziona così. ;)
Ogni volta che il problema viene risolto puoi chiudere te la discussione, ne hai i permessi.
Perfetto,alla prossima :).Chiudo
 
Stato
Discussione chiusa ad ulteriori risposte.