2010-07-13 4 views
16

In Java sto utilizzando il metodo substring() e non sono sicuro del motivo per cui non genera un errore "fuori indice".Perché "fuori campo" non viene generato per "sottostringa (startIndex, endIndex)"

La stringa abcde ha inizio indice da 0 a 4, ma il metodo substring() prende startIndex e endIndex come argomenti basato sul fatto che posso chiamare foo.substring (0) e ricevere "ABCDE".

Quindi perché la sottostringa (5) funziona? Quell'indice dovrebbe essere fuori portata. Qual è la spiegazione?

/* 
1234 
abcde 
*/ 
String foo = "abcde"; 
System.out.println(foo.substring(0)); 
System.out.println(foo.substring(1)); 
System.out.println(foo.substring(2)); 
System.out.println(foo.substring(3)); 
System.out.println(foo.substring(4)); 
System.out.println(foo.substring(5)); 

This uscite di codice:

abcde 
bcde 
cde 
de 
e 
    //foo.substring(5) output nothing here, isn't this out of range? 

Se si sostituisce 5 con 6:

foo.substring(6) 

Poi ottengo errore:

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: 
    String index out of range: -1 

risposta

18

Secondo il Java API doc, sottostringa getta un errore quando l'indice di partenza è superiore alla lunghezza della stringa.

IndexOutOfBoundsException - if beginIndex is negative or larger than the length of this String object.

In realtà, danno un esempio molto come la tua:

"emptiness".substring(9) returns "" (an empty string) 

Credo che questo significa che è meglio pensare a una stringa Java come il seguente, dove l'indice è avvolto in |:

|0| A |1| B |2| C |3| D |4| E |5| 

Vale a dire che una stringa ha sia un indice di inizio che di fine.

+0

Ahh! grazie per il tip, stavo guardando la stessa pagina doc ma non sapevo che dovevo scorrere fino in fondo per ottenere maggiori dettagli ... –

+4

Vorrei che il javadoc possa avere una nota su questo, o ragazzi disattenti come me aspettarsi 'IndexOutOfBoundsException' se initIndex = String.length(). –

2

sottostringhe (5) indica un indice esistente ... capita semplicemente di indicare un vuoto stringa. la sottostringa (6), d'altra parte, è solo una pazzia. :)

14

Quando si esegue foo.substring(5), la sottostringa inizia dalla posizione subito dopo la "e" e termina alla fine della stringa. Per inciso, la posizione iniziale e finale è la stessa. Quindi, stringa vuota. Si può pensare che l'indice non sia un carattere reale nella stringa, ma una posizione tra i caratteri.

 --------------------- 
String: | a | b | c | d | e | 
     --------------------- 
Index: 0 1 2 3 4 5 
3

Da String API javadoc:

public String substring(int beginIndex) 
    Returns a new string that is a substring of this 
    string. The substring begins with the "" character 
    at the specified index and extends to the end of this string. 

public String substring(int beginIndex, int endIndex) 
    Returns a new string that is a substring of this 
    string. The substring begins at the specified beginIndex 
    and extends to the character at index endIndex - 1. Thus 
    the length of the substring is endIndex-beginIndex. 

Esempi:

"unhappy".substring(2) returns "happy" 
"Harbison".substring(3) returns "bison" 
"emptiness".substring(9) returns "" (an empty string) 

"hamburger".substring(4, 8) returns "urge" 
"smiles".substring(1, 5) returns "mile" 

Parametri:

beginIndex - the beginning index, inclusive. 
Returns: 
the specified substring. 
Throws: 
IndexOutOfBoundsException - if beginIndex is negative or 
larger than the length of this String object. 

====

Quindi questo è di progettazione. Se si assegna l'indice come dimensione della stringa, restituisce una stringa vuota.

3

So che questo thread è piuttosto vecchio, ma questo è un problema fondamentale che penso giustifichi un chiarimento.

La domanda è corretta. Lo vedo come un errore del software nel metodo Java String.substring (int beginIndex, int endIndex).

http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#substring%28int,%20int%29.

Dal Java Docs https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html

Java Arrays

Java/C/C++ e di ogni altra lingua che io sappia non considera l'indice dell'array come il 'divisorio' tra gli elementi dell'array.

Parametri: beginIndex - l'indice iniziale, incluso. endIndex - l'indice finale, esclusivo.

O endIndex è misnamed perché la lingua non consente l'accesso di memoria a un indirizzo al endIndex + 1 che è necessario includere l'ultimo elemento dell'array O endIndex è mis-definiti da: endIndex - l'indice finale, compreso .

Il caso più probabile è che il secondo parametro sia stato erroneamente denominato. Dovrebbe essere: lunghezza: la lunghezza della stringa desiderata inizia da beginIndex.

Sappiamo che Gosling ha basato la sintassi Java sui linguaggi C/C++ per familiarità. Dalla classe di stringhe C+++ http://www.cplusplus.com/reference/string/string/substr/ vediamo che la definizione del metodo è:

substr string (size_t pos = 0, size_t len ​​= npos) const;

Si noti che il secondo parametro nella definizione del metodo è 'len' per la lunghezza.

len Numero di caratteri da includere nella sottostringa (se la stringa è più breve, come numero possibile di caratteri vengono utilizzati).

testString ha 10 caratteri, posizioni di indice 0 a 9. Specifica di un endIndex di 10 dovrebbe sempre gettare l'IndexOutOfBoundsException() perché testString ha endIndex di 10.

Se testiamo il metodo in JUnit con valori concreti guardando il metodo C++, ci aspettiamo:

String testString = "testString"; assertThat (testString.substring (4, 6), equalTo ("String"));

ma naturalmente otteniamo previsto: "Stringa", ma era "St"

La lunghezza del testString dall'indice 0 a char 'g' a 'String' è di 10 caratteri. Se si utilizza 10 come parametro 'endIndex',

String testString = "testString"; assertThat (testString.substring (4, 10), equalTo ("String"));

"Pass" da JUnit.

Se rinominiamo il parametro 2 in "lengthOfSubstringFromIndex0" non è necessario eseguire il conteggio endIndex - 1 e non getta mai IndexOutOfBoundsException() che è previsto quando si specifica un endIndex, 10, che è fuori intervallo per l'array sottostante. http://docs.oracle.com/javase/7/docs/api/java/lang/IndexOutOfBoundsException.html

Questa è solo una di quelle volte che devi ricordare l'idiosincrasia di questo metodo. Il secondo parametro non è denominato correttamente. La firma del metodo Java dovrebbe essere:

public String substring(int beginIndex, 
      int lengthOfSubstringFromIndex0) 

o il metodo ridefinito in modo che corrisponda C++ metodo stringa :: substr. Ridefinire ovviamente significherebbe riscrivere l'intero internet, quindi non è probabile.