RISOLTO Problema Java con Scanner

Pubblicità
Stato
Discussione chiusa ad ulteriori risposte.

Akrilix

Nuovo Utente
Messaggi
145
Reazioni
32
Punteggio
39
Ciao a tutti,
per imparare ad usare l'ereditarietà dei metodi e delle classi ho cominciato a scrivere un semplice programmino/giochino:
Ho due classi figlie, "FiatPanda" e "Porsche911", entrambe ereditano da altre due classi genitori ("Veicolo" e "Auto") i metodi e i vari parametri. Questo programmino deve far scegliere all'utente che auto utilizzare e in base a quella scelta si avranno, oltre alle caratteristiche comuni prese da "Veicolo" e "Auto", anche le proprie dell'auto esclusive. Una volta scelta, l'utente seleziona la direzione (S/D), la marcia (R/1/2/...) e la velocità (0-250 KM/H) e in base ai valori inseriti il programma sorteggia randomicamente se l'utente abbia fatto o no un incidente.

ES:
Fiat Panda 2^ marcia a 70 KM/H direzione destra: incidente non avvenuto.
Porsche 911 5^ marcia a 230 KM/H direzione sinistra: incidente avvenuto.

N.B.: i valori delle marce sono fittizi e con l'unico scopo di rendere lo sviluppo più confortevole.

Ad influenzare il random ci sarebbero (sempre io riesca ad implementarli) dei parametri casuali come ad esempio la pioggia, il motore ingolfato (più probabile per la Fiat), guidatore ubriaco, poco traffico...

Non ho ancora fatto niente però, ho solo cominciato a creare i 3 metodi principali nella classe "Veicolo", ma mi esce questo errore:

/---------------------------------------------------------------------------------------------------------------------\
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Unknown Source)
at java.util.Scanner.next(Unknown Source)
at Veicolo.numeroMarcia(
Veicolo.java:67)
at Main.main(
Main.java:8)
\ ---------------------------------------------------------------------------------------------------------------------/

Posto qui il codice della classe "Main" e "Veicolo":

Java:
public class Main {
  
    public static void main (String [] args) {
      
        Veicolo testFunzionare = new Veicolo ();
      
        testFunzionare.sinistraDestra();
        testFunzionare.numeroMarcia();
        testFunzionare.kilometriOrari();
      
    }
  
}

Java:
import java.util.Scanner;

public class Veicolo {
  
    private String direzione = "", marciaStringa = "";
    private int marciaNumero = 0, velocità = 0, controlloMarcia = 0, controlloKilometri = 0;
  
    public Veicolo (/*String direzione, int marcia, int velocità*/) {
      
//        this.direzione = direzione;
//        this.marcia = marcia;
//        this.velocità = velocità;
      
    }
  
    public void sinistraDestra () {
      
        Scanner inputValore = new Scanner (System.in);
      
        System.out.print ("In che direzione vorresti andasse la tua auto? [S/D]: ");
      
        do {
          
            direzione = inputValore.next ();
          
            direzione = direzione.toUpperCase ();
          
            if (!direzione.equals ("S") && !direzione.equals ("D"))
                System.out.print ("Hai inserito una direzione SBAGLIATA. [S/D]: ");
          
        } while (!direzione.equals ("S") && !direzione.equals ("D"));
      
        inputValore.close ();
      
    }
  
    public void numeroMarcia () {
      
        Scanner inputValore = new Scanner (System.in);
      
        System.out.print ("Che marcia vorresti usare? [R/1/2/3/4/5]: ");
      
        boolean controlloValore;
      
        do {
          
            controlloValore = inputValore.hasNextInt ();
          
            if (controlloValore) {
              
                marciaNumero = inputValore.nextInt ();
              
                if (marciaNumero < 1 || marciaNumero > 5) {
                  
                    System.out.print ("Hai inserito una marcia SBAGLIATA. [R/1/2/3/4/5]: ");
                  
                    continue;
                  
                }
              
                controlloMarcia = 1;
              
            }
          
            else {
              
                marciaStringa = inputValore.next ();
              
                marciaStringa = marciaStringa.toUpperCase ();
              
                if (!marciaStringa.equals("R")) {
                  
                    System.out.print ("Hai inserito una marcia SBAGLIATA. [R/1/2/3/4/5]: ");
                  
                    inputValore.nextLine ();
                  
                    continue;
                  
                }
              
                controlloMarcia = 2;
              
            }
          
        } while ((marciaNumero < 1 || marciaNumero > 5) && !marciaStringa.equals("R"));
      
        //inputValore.close ();
      
    }
  
    public void kilometriOrari () {
      
        Scanner inputValore = new Scanner (System.in);
      
        System.out.println ("A quanti KM/H vorresti andare? [0 - 250]. ");
        System.out.println ("Marcia R: 0-25.");
        System.out.println ("Marcia 1: 0-50.");
        System.out.println ("Marcia 2: 50-100.");
        System.out.println ("Marcia 3: 100-150.");
        System.out.println ("Marcia 4: 150-200.");
        System.out.println ("Marcia 5: 200-250.");
        System.out.print ("Inserisci QUI: ");
      
        boolean controlloValore;
      
        do {
          
            controlloValore = inputValore.hasNextInt ();
          
            if (controlloValore) {
              
                velocità = inputValore.nextInt ();
              
                if (velocità < 0 || velocità > 250) {
                  
                    System.out.print ("Hai inserito dei KM/H SBAGLIATI. [0-250]: ");
                  
                    continue;
                  
                }
              
                if (controlloMarcia == 1) {
                  
                    switch (marciaNumero) {
                  
                    case 1:
                      
                        if (velocità > 50) {
                            System.out.print ("KM/H non validi per la marcia. [0-50]: ");
                            continue;
                        }
                      
                        System.out.println ("Hai deciso di andare a " + velocità + " KM/H");
                      
                        controlloKilometri ++;
                      
                        break;
                      
                    case 2:
                      
                        if (velocità < 50 || velocità > 100) {
                            System.out.print ("KM/H non validi per la marcia. [50-100]: ");
                            continue;
                        }
                      
                        System.out.println ("Hai deciso di andare a " + velocità + " KM/H");
                      
                        controlloKilometri ++;
                      
                        break;
                  
                    case 3:
                      
                        if (velocità < 100 || velocità > 150) {
                            System.out.print ("KM/H non validi per la marcia. [100-150]: ");
                            continue;
                        }
                      
                        System.out.println ("Hai deciso di andare a " + velocità + " KM/H");
                      
                        controlloKilometri ++;
                      
                        break;
              
                    case 4:
                      
                        if (velocità < 150 || velocità > 200) {
                            System.out.print ("KM/H non validi per la marcia. [150-200]: ");
                            continue;
                        }
                      
                        System.out.println ("Hai deciso di andare a " + velocità + " KM/H");
                      
                        controlloKilometri ++;
                      
                        break;
                      
                    case 5:
                      
                        if (velocità < 200 || velocità > 250) {
                            System.out.print ("KM/H non validi per la marcia. [200-250]: ");
                            continue;
                        }
                      
                        System.out.println ("Hai deciso di andare a " + velocità + " KM/H");
                      
                        controlloKilometri ++;
                      
                        break;
                  
                    }
                  
                }
              
                else {
                  
                    if (velocità > 25) {
                        System.out.print ("KM/H non validi per la marcia. [200-250]: ");
                        continue;
                    }
                  
                    System.out.println ("Hai deciso di andare a " + velocità + " KM/H");
                  
                    controlloKilometri ++;
                  
                }
              
            }
          
            else {
              
                System.out.print ("Hai inserito una LETTERA nel valore. Reinserisci: ");
              
                inputValore.nextLine ();
              
            }
          
        } while ((velocità < 0 || velocità > 250) && controlloKilometri != 1);
      
        inputValore.close ();
      
    }
  
}

Scusate per la mancanza di commenti ma non ho fatto in tempo a metterli.

P.S.: il metodo kilometriOrari non l'ho ancora testato, se ci fossero errori di sintassi è per quello.
 
Non l'ho eseguito ma ad occhio - anche se sono arrugginito con Java - penso proprio che il problema sia nell'utilizzo che fai di Scanner. Bene il controllo su hasNextInt() prima della lettura, ma quando non è un int (posto che dovresti verificare se esiste il token), tu usi next(). Questo metodo, se non è cambiato nelle ultime release, restituisce il token: questo token però termina sullo spazio. Quindi se vuoi leggere una stringa dovresti richiamare nextLine().

Cito la doc:
A simple text scanner which can parse primitive types and strings using regular expressions.
A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace.

quindi o leggi una stringa, o puoi anche settare un altro token. Se vuoi usare l'Invio (CRLF), puoi fare:
Java:
Scanner scanner = new Scanner(System.in);
scanner.useDelimiter("\r\n");



Mi permetti alcune osservazioni?
Le inizializzazioni: usa sempre i costruttori. Se non ti serve dare valori specifici, allora non usarle, ma evita di inizializzarle; avranno i valori di default. Le String saranno a null (in quanto oggetti), mentre gli interi saranno a 0.

L'unico appunto, che è il più importante, è un consiglio per il futuro: tieni sempre presente che i metodi che svolgono un qualche compito, di solito si limitano a quello, e non stampano del testo a video.
Inoltre, quello che è di fatto un menu di scelta, sarebbe meglio inserirlo in un ciclo (magari un do/while) così da gestire anche inserimenti errati, e ripetere nuovamente il menu di scelta.
 
ciao un appunto importante per quando scrivi codice, scrivilo in inglese e non in italiano tipo (classe veicolo falla diventare classe
vehicle). Questo perchè nel momento in cui utilizzerai forum di supporto di alcuni prodotti o librerie e ti chiedono degli esempi vorranno il codice inglessizzato.
 
@DispatchCode,
innanzitutto grazie per la risposta. Quando apro il computer provo a sistemare e vedere se la soluzione da te indicata funziona. Per quanto riguarda la dichiarazione dei costruttori, purtroppo è un problema grave di abitudine: anche il nostro professore oggi ci ha fatto un enorme cazziatone in quanto nella verifica, oltre a non usare i costruttori, compiliamo più codice nel Main anziché nelle apposite classi con i metodi, perdendo così uno dei punti fondamentali di Java, ovvero gli oggetti, continuando a stilare il codice con uno sviluppo top-down in quanto abituati così con C++. A dire la verità non ho ben capito anch’io come usarli, soprattutto quando è l’utente a inserire i valori. Dovrei fare così?

Java:
public class Main {
  
    public static void main (String [] args) {
        
        testFunzionare.sinistraDestra();
        testFunzionare.numeroMarcia();
        testFunzionare.kilometriOrari();

        Veicolo testFunzionare = new Veicolo (direzione, marciaStringa, marciaNumero, velocità);

    }
  
}

Nella classe “Veicolo” invece dovrei togliere le dichiarazioni all’inizio e de-commentare il costruttore aggiungendo marciStringa e marciaNumero?

Per il menù a scelta penso di farlo in un’altra classe ereditando i metodi.
————————————————
@Skills07
Provvederò a tradurre tutti i nomi in inglese. Sai se esiste un metodo per rinominare tutte le variabili con lo stesso nome in un colpo?
 
quello dipende molto dall'editor che usi
 
Sisi, appena fatto. Grazie del consiglio.
--- i due messaggi sono stati uniti ---
@DispatchCode,
ho fatto così, va bene?

Java:
public class Main {
    
    public static void main (String [] args) {
        
        Veicolo testFunzionare = new Veicolo (null, null, 0, 0);
        
        testFunzionare.sinistraDestra();
        testFunzionare.numeroMarcia();
        testFunzionare.kilometriOrari();
        
        System.out.println (testFunzionare.getDirection ());
        //Mi ritorna effettivamente il valore, quindi lo ha salvato.
        
    }
    
}

Java:
import java.util.Scanner;

public class Veicolo {
    
    private String direction, stringTransmission;
    private int numberTransmission, speed, checkTransmission, checkKilometers;
    
    public Veicolo (String direction, String stringTransmission, int numberTransmission, int speed) {
        
        this.direction = direction;
        this.stringTransmission = stringTransmission;
        this.numberTransmission = numberTransmission;
        this.speed = speed;
        
    }

    ...

}

Funzionano così i costruttori?
 
Ultima modifica:
Per quanto riguarda la dichiarazione dei costruttori, purtroppo è un problema grave di abitudine: anche il nostro professore oggi ci ha fatto un enorme cazziatone in quanto nella verifica, oltre a non usare i costruttori, compiliamo più codice nel Main anziché nelle apposite classi con i metodi, perdendo così uno dei punti fondamentali di Java, ovvero gli oggetti, continuando a stilare il codice con uno sviluppo top-down in quanto abituati così con C++. A dire la verità non ho ben capito anch’io come usarli, soprattutto quando è l’utente a inserire i valori.

Nella classe “Veicolo” invece dovrei togliere le dichiarazioni all’inizio e de-commentare il costruttore aggiungendo marciStringa e marciaNumero?

Per il menù a scelta penso di farlo in un’altra classe ereditando i metodi.

Non ha tutti i torti il tuo docente. Anche in C++ è comunque la stessa cosa; solo che purtroppo a scuola viene sempre affrontato dando un'idea sbagliata. Si prende in pratica il C++, gli si toglie la OOP, si tiene "iostream" e lo si trasforma in un misto tra C e C++.

Sisi, appena fatto. Grazie del consiglio.
--- i due messaggi sono stati uniti ---
@DispatchCode,
ho fatto così, va bene?

Java:
public class Main {
  
    public static void main (String [] args) {
      
        Veicolo testFunzionare = new Veicolo (null, null, 0, 0);
      
        testFunzionare.sinistraDestra();
        testFunzionare.numeroMarcia();
        testFunzionare.kilometriOrari();
      
        System.out.println (testFunzionare.getDirection ());
        //Mi ritorna effettivamente il valore, quindi lo ha salvato.
      
    }
  
}

Java:
import java.util.Scanner;

public class Veicolo {
  
    private String direction, stringTransmission;
    private int numberTransmission, speed, checkTransmission, checkKilometers;
  
    public Veicolo (String direction, String stringTransmission, int numberTransmission, int speed) {
      
        this.direction = direction;
        this.stringTransmission = stringTransmission;
        this.numberTransmission = numberTransmission;
        this.speed = speed;
      
    }

    ...

}

Funzionano così i costruttori?

Riguardo ai costruttori, vedila così: ha senso passare loro dei parametri quando devi dare un valore iniziale, diverso da quello di default. Nel tuo caso è inutile richiamare il costruttore con quei parametri, in quanto il valore di default è quello che gli passi.
Sarebbe meglio creare un Veicolo senza parametri.

A parte questo, non stai sbagliando. Considera che con le applicazioni testuali è tutta un'altra cosa rispetto alla GUI: ai tempi in cui Swing era la libreria consigliata ed utilizzata maggiormente (ora c'è JavaFx), il main() serviva solo a lanciare il thread della GUI, il quale creava un oggetto per inizializzare la finestra.

Piccolo esempio.
Immagina di avere una classe che gestisce dei Veicoli: questa classe usa un array per memorizzare tutti i veicoli, ma ha una capienza massima: il costruttore di questa classe potrebbe proprio passare questo valore.

Java:
class Veicoli {
    private Veicolo []veicoli;

    Veicoli(int capacity) {
        veicoli = new Veicolo[capacity];
    }
....

comunqe vedendo gli altri aspetti della OOP (ereditarietà e polimorfismo) e facendo pratica, tutto sarà più chiaro in futuro.;)
 
Ciao, scusa se ti rispondo solo ora ma ho fatto una grande decisione oggi: mi sono preso il libro "Java 11" della Apogeo da affiancare al mio studio. Credo di sfruttare questi giorni prima delle vacanze per dare un mega ripassatone e poi riprendere lo studio verso il 27-28. Sono contento della mia decisione, mi farò vivo presto comunque in caso di altri dubbi.

Buona serata.
 
Bene, mi fa piacere la tua decisione (non è così frequente notare dell'interesse).
In caso di dubbi durante la lettura, siamo qui.
 
Stato
Discussione chiusa ad ulteriori risposte.
Pubblicità
Pubblicità
Indietro
Top