Wie wende ich die for-each-Schleife auf jedes Zeichen in einem String an?

189

Ich möchte also für jedes Zeichen in einer Zeichenfolge iterieren.

Also dachte ich:

for (char c : "xyz")

aber ich bekomme einen Compilerfehler:

MyClass.java:20: foreach not applicable to expression type

Wie kann ich das machen?

Lyndon White
quelle

Antworten:

333

Der einfachste Weg für jeden charin einem Stringist toCharArray():

for (char ch: "xyz".toCharArray()) {
}

Dies gibt Ihnen die Prägnanz für jedes Konstrukt, muss aber leider String(was unveränderlich ist) eine defensive Kopie ausführen, um das char[](was veränderlich ist) zu generieren , so dass es einige Kostenstrafen gibt.

Aus der Dokumentation :

[ toCharArray()gibt] ein neu zugewiesenes Zeichenarray zurück, dessen Länge der Länge dieser Zeichenfolge entspricht und dessen Inhalt so initialisiert wird, dass er die durch diese Zeichenfolge dargestellte Zeichenfolge enthält.

Es gibt ausführlichere Möglichkeiten, Zeichen in einem Array zu durchlaufen (regulär für Schleife CharacterIteratorusw.), aber wenn Sie bereit sind, die Kosten dafür zu zahlen, toCharArray()ist jede die prägnanteste.

Polygenschmierstoffe
quelle
1
Wird der Compiler erkennen, dass keine echte Kopie benötigt wird, und die entsprechenden Optimierungen anwenden?
Pacerier
1
@Pacerier Nein, die aktuellen Java-Compiler werden den Code niemals optimieren.
RAnders00
1
@ RAnders00 Also wird in diesem Fall toCharArray( )3 mal aufgerufen?
Denverver9 9.
1
Bei einer Stringlänge von beträgt die 211900000Zeit bis zur Fertigstellung for (char c : str.toCharArray()) { }~ 250 ms und die Zeit bis zur Fertigstellung for (char c : charArray) { }< 10 ms . Natürlich hängen diese Zeitwerte von der Hardware ab, aber zum Mitnehmen ist, dass eine Methode erheblich teurer ist als die andere.
denvercoder9
7
@ RafiduzzamanSonnet: Nein, das toCharArray()befindet sich nicht im Loop-Body. Es wird nur einmal aufgerufen, und dann durchläuft die Schleife das resultierende Array. (Die for-each-Schleife unterscheidet sich von der allgemeinen for-schleife, die die Stoppbedingung bei jeder Iteration auswertet.)
nicht nur-Yeti
50
String s = "xyz";
for(int i = 0; i < s.length(); i++)
{
   char c = s.charAt(i);
}

 

Matthew Flaschen
quelle
7
OP erwartet eine verbesserte for-Schleife.
AmitG
3
Abgestimmt, weil dies nicht das ist, wonach OP gefragt hat. Dies ist zwar eine gültige Lösung, aber es ist absolut nicht das, was gefragt wird
Sirenen
1
Egal was das OP erwartet hat, dies hat eine bessere Leistung als für jeden, denke ich.
Eric Wang
9

Eine weitere nützliche Lösung ist, dass Sie mit dieser Zeichenfolge als Array von Zeichenfolgen arbeiten können

for (String s : "xyz".split("")) {
    System.out.println(s);
}
Kyxap
quelle
Elegant, aber leider funktioniert es nicht, wenn Elemente der Zeichenfolge split()mehr als einem Java-Zeichen zugeordnet sind, was bei fast allen Emoticons der Fall ist. Zum Beispiel wird diese Variation Ihres Beispiels vier statt drei Mal for (String s : "x😁z".split("")) { System.out.println(s); }
wiederholt
5

Sie müssen das String-Objekt mit der toCharArray() -Methode der String-Klasse in ein Array von char konvertieren :

String str = "xyz";
char arr[] = str.toCharArray(); // convert the String object to array of char

// iterate over the array using the for-each loop.       
for(char c: arr){
    System.out.println(c);
}
Codaddict
quelle
4

In Java 8 können wir es lösen als:

String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));    

Die Methode chars () gibt ein IntStreamwie in doc erwähnt zurück :

Gibt einen Stream von int Null zurück, der die Zeichenwerte aus dieser Sequenz erweitert. Jedes Zeichen, das einem Ersatzcodepunkt zugeordnet ist, wird nicht interpretiert durchlaufen. Wenn die Sequenz während des Lesens des Streams mutiert ist, ist das Ergebnis undefiniert.

Warum verwenden forEachOrderedund nicht forEach?

Das Verhalten von forEachist explizit nicht deterministisch, wenn das forEachOrderedeine Aktion für jedes Element dieses Streams in der Begegnungsreihenfolge des Streams ausführt, wenn der Stream eine definierte Begegnungsreihenfolge hat. Dies forEachgarantiert nicht, dass die Bestellung beibehalten wird. Überprüfen Sie auch diese Frage für mehr.

Wir könnten auch codePoints()zum Drucken verwenden. Weitere Informationen finden Sie in dieser Antwort .

akhil_mittal
quelle
Dadurch werden mehrere Objekte erstellt, sodass diese Antwort nicht vollständig ist, ohne die Einschränkung, dass dies möglicherweise weniger effizient ist als eine einfache indizierte Schleife.
Werkzeugschmied
4

Leider macht Java keine StringImplementierung Iterable<Character>. Dies könnte leicht getan werden. Es gibt StringCharacterIteratoraber das implementiert nicht einmal Iterator... Also mach dein eigenes:

public class CharSequenceCharacterIterable implements Iterable<Character> {
    private CharSequence cs;

    public CharSequenceCharacterIterable(CharSequence cs) {
        this.cs = cs;
    }

    @Override
    public Iterator<Character> iterator() {
        return new Iterator<Character>() {
            private int index = 0;

            @Override
            public boolean hasNext() {
                return index < cs.length();
            }

            @Override
            public Character next() {
                return cs.charAt(index++);
            }
        };
    }
}

Jetzt können Sie (etwas) leicht laufen for (char c : new CharSequenceCharacterIterable("xyz"))...

Ossifer
quelle
3

Wenn Sie Java 8 verwenden, können Sie chars()a verwenden String, um ein StreamZeichen zu erhalten, aber Sie müssen das intZurück zu a setzen, charwenn chars()ein zurückgegeben wird IntStream.

"xyz".chars().forEach(i -> System.out.print((char)i));

Wenn Sie Java 8 mit Eclipse-Sammlungen verwenden , können Sie die CharAdapterKlassenmethode forEachmit einem Lambda oder einer Methodenreferenz verwenden, um alle Zeichen in a zu durchlaufen String.

Strings.asChars("xyz").forEach(c -> System.out.print(c));

In diesem speziellen Beispiel könnte auch eine Methodenreferenz verwendet werden.

Strings.asChars("xyz").forEach(System.out::print)

Hinweis: Ich bin ein Committer für Eclipse-Sammlungen.

Donald Raab
quelle
1

In diesem Fall können Sie auch ein Lambda verwenden.

    String s = "xyz";
    IntStream.range(0, s.length()).forEach(i -> {
        char c = s.charAt(i);
    });
ander4y748
quelle
-7

Für Travers kann ein String auch charAt()mit dem String verwendet werden.

mögen :

String str = "xyz"; // given String
char st = str.charAt(0); // for example we take 0 index element 
System.out.println(st); // print the char at 0 index 

charAt() ist eine Methode zur Behandlung von Zeichenfolgen in Java, mit deren Hilfe die Zeichenfolge für ein bestimmtes Zeichen durchlaufen werden kann.

user1690439
quelle
2
Weißt du was for (char st: "xyz".toCharArray()) {}ist?
AmitG
Dies wird nicht kompiliert.
Maroun
-1 off-topic (Thema: für jeden), und verwenden Sie charAt anstelle von charAT
peenut