PDA

View Full Version : [Java] Problema in esecuzione del metodo nextLine


[Kendall]
25-03-2011, 15:42
Salve ragazzi, volevo chiedervi un consulto... Mi sto impratichendo di Java e facevo qualche esercizietto proposto... In pratica è un semplice programma di inserimento di una tabella caratteri e ricerca all'interno della stessa... Tutto ok, tranne un particolare.

Quando inserisco nella tabella i caratteri, nonchè poi quando vado ad inserire il carattere da ricercare, mi permette di utilizzare il metodo:

tabella[i][j] = input.next().charAt(0);

e non il metodo

tabella[i][j] = input.nextLine().charAt(0);

In questo secondo caso mi dà il classico errore in fase di esecuzione OutOfBound per la Stringa inserita.
Io però ricordo assolutamente di aver già utilizzato in un altro programmino la versione con nextLine, senza errore alcuno...
Conosco le differenze tra il next, e il nextLine (la prima prende la prima parola, la seconda l'intera riga, spazi inclusi, se non erro), ma non capisco in questo caso perchè dia un simile errore.
Ecco il codice del programma comunque.

import java.util.Scanner;

class Esercizio15 {
public static void main(String argv[]) {
char tabella[][];
char ricerca;
int r, c;
int i, j;
int contatore;
Scanner input = new Scanner(System.in);

System.out.println();

System.out.println("Inserire le dimensioni della tabella da compilare:");
do {
System.out.print("Righe = ");
r = input.nextInt();
if (r<2) {
System.out.println("Una tabella deve contenere almeno due righe e due colonne. Riprovare...");
}
} while (r<2);
do {
System.out.print("Colonne = ");
c = input.nextInt();
if (c<2) {
System.out.println("Una tabella deve contenere almeno due righe e due colonne. Riprovare...");
}
} while (c<2);

tabella = new char[r][c];

System.out.println();

System.out.println("Inserire i caratteri nella tabella, seguendo l'ordine indicato a schermo:\n");
for (i=0 ; i<r ; i++) {
for (j=0 ; j<c ; j++) {
System.out.print("Tabella(" + (i+1) + "," + (j+1) + ") = ");
tabella[i][j] = input.next().charAt(0);
}
System.out.println();
}

System.out.println("\n");

System.out.println("TABELLA CARATTERI");
for (i=0 ; i<r ; i++) {
System.out.print("|");
for (j=0 ; j<c ; j++) {
System.out.print(" " + tabella[i][j] + " ");
}
System.out.print("|");
System.out.println();
}

System.out.println();

System.out.print("Inserire il carattere da ricercare: ");
ricerca = input.next().charAt(0);
contatore = 0;
for (i=0 ; i<r ; i++) {
for (j=0 ; j<c ; j++) {
if (tabella[i][j] == ricerca) {
System.out.println("Trovato! Riga " + (i+1) + ", Colonna " + (j+1) + ".");
contatore += 1;
}
}
}
if (contatore == 0) {
System.out.println("Carattere non trovato!");
}

System.out.println();
}
}

Qualche idea?

banryu79
25-03-2011, 15:55
Puoi postare lo stack trace dell'eccezione?

[Kendall]
25-03-2011, 16:01
Puoi postare lo stack trace dell'eccezione?

Inserire le dimensioni della tabella da compilare:
Righe = 4
Colonne = 6

Inserire i caratteri nella tabella, seguendo l'ordine indicato a schermo:

Tabella(1,1) = Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.lang.String.charAt(String.java:694)
at Esercizio15.main(Esercizio15.java:51)


Però non capisco. La posizione 0 di una stringa dovrebbe essere sempre e comunque il primo carattere che la compone (come un array di qualsiasi altro tipo). Ed infatti con next().charAt(0) funziona...

Mumble mumble...

banryu79
25-03-2011, 16:08
Stai usando uno Scanner collegato allo stream di standard input (System.in)

Scanner funziona in base ad un delimiter, che è un pattern rispetto al quale esegue dei match per isolare le parti di input considerate come token validi.

Siccome non setti esplicitamente il delimiter, viene usato quello di default che matcha tutti i whitespace (in sostanza "spazi vuoti" e i caratteri di "fine linea").

Usare next() o nextLine() non è esattamente la stessa cosa.
next() è token-centrica, ed è così documentata:

public String next()

Finds and returns the next complete token from this scanner. A complete token is preceded and followed by input that matches the delimiter pattern. This method may block while waiting for input to scan, even if a previous invocation of hasNext() returned true.

Qui hai la garanzia che la String restituita è un token valido, per come sono definiti i token in base al delimiter impostato. Nel tuo caso un token valido è una qualsiasi stringa preceduta e seguita da whitespace, il che implica che una stringa vuota non da luogo a match e dunque non verrà restituita da next().

nextLine() invece non è token-centrica ma line-centrica, per così dire. E' documentata così:

public String nextLine()

Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line.

Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present.

nextLine() restituisce dunque una stringa, ma non è detto che quella stringa debba essere per forza un token definito dalle regole di match relative al delimiter scelto (come invece era per next). Ergo nextLine() può restituire una linea vuota, ed è (credo) il tuo caso: alla prima lettura di System.in, in System.in stesso c'è solo il carattere di fine-linea, nextLine skippa oltre e restituisce tutto quello che ha incontrato prima del fine-linea stesso, ovvero una bella String vuota (String vuota = "").

Tu provi ad accedere all'indice 0 del sottostante array di char contenuto dalla String e boom, ti bechi lo StringIndexOutOfBounds ;)

[Kendall]
25-03-2011, 17:18
Stai usando uno Scanner collegato allo stream di standard input (System.in)

Scanner funziona in base ad un delimiter, che è un pattern rispetto al quale esegue dei match per isolare le parti di input considerate come token validi.

Siccome non setti esplicitamente il delimiter, viene usato quello di default che matcha tutti i whitespace (in sostanza "spazi vuoti" e i caratteri di "fine linea").

Usare next() o nextLine() non è esattamente la stessa cosa.
next() è token-centrica, ed è così documentata:

Qui hai la garanzia che la String restituita è un token valido, per come sono definiti i token in base al delimiter impostato. Nel tuo caso un token valido è una qualsiasi stringa preceduta e seguita da whitespace, il che implica che una stringa vuota non da luogo a match e dunque non verrà restituita da next().

nextLine() invece non è token-centrica ma line-centrica, per così dire. E' documentata così:

nextLine() restituisce dunque una stringa, ma non è detto che quella stringa debba essere per forza un token definito dalle regole di match relative al delimiter scelto (come invece era per next). Ergo nextLine() può restituire una linea vuota, ed è (credo) il tuo caso: alla prima lettura di System.in, in System.in stesso c'è solo il carattere di fine-linea, nextLine skippa oltre e restituisce tutto quello che ha incontrato prima del fine-linea stesso, ovvero una bella String vuota (String vuota = "").

Tu provi ad accedere all'indice 0 del sottostante array di char contenuto dalla String e boom, ti bechi lo StringIndexOutOfBounds ;)

Grazie mille per la spiegazione... Purtroppo devo ancora arrivare nella sezione che tratta in maniera approfondita questi argomenti e non è la prima volta infatti che il .nextLine mi dà problemi.
Quindi, se io volessi leggere l'intera riga, nel mio caso preciso (non so, magari per aver la possibilità di inserire nella tabella creata anche il carattere di spazio), dovrei prima di effettuare la lettura, dare un comando di input.nextLine(); a vuoto, così da passare alla riga successiva ed attendere l'input da tastiera? Ho detto una castroneria?