Як застосувати цикл for-every до кожного символу в рядку?


189

Тому я хочу повторити кожен символ у рядку.

Тому я подумав:

for (char c : "xyz")

але я отримую помилку компілятора:

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

Як я можу це зробити?

Відповіді:


333

Найпростіший спосіб для кожного charз них - Stringце використовувати toCharArray():

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

Це дає вам лаконічність для кожної конструкції, але, на жаль String(яка незмінна) повинна виконати захисну копію для створенняchar[] (що є змінним), тому є певна вартість штрафу.

З документації :

[ toCharArray()повертає] щойно виділений масив символів , довжина якого - довжина цієї рядка та вміст якого ініціалізовано, щоб містити послідовність символів, представлену цією рядком.

Існує більше багатослівних способів ітерації символів у масиві (звичайний цикл CharacterIteratorтощо), але якщо ви готові заплатити вартість, toCharArray()кожен є найбільш стислим.


1
Чи визнає компілятор, що справжня копія не потрібна, і застосує відповідні оптимізації?
Пейсьєр

1
@Pacerier Ні, поточні компілятори Java ніколи не оптимізують код.
RAnders00

1
@ RAnders00 Отже, у цьому випадку toCharArray( )називається 3 рази?
denvercoder9

1
Тривалість струни - 211900000час, необхідний для завершення, for (char c : str.toCharArray()) { }- 250 мс, а час, необхідний для виконання, for (char c : charArray) { }- <10 мс. Звичайно, ці значення часу залежатимуть від апаратного забезпечення, але, наприклад, один метод значно затратний, ніж інший.
denvercoder9

7
@RafiduzzamanSonnet: Ні, toCharArray()це не всередині циклу; він викликається лише один раз, а потім цикл перебирається через цей результуючий масив. (Цикл для кожного циклу відрізняється від загального for-loop, який оцінює умову зупинки кожну ітерацію.)
not-just-yeti

50
String s = "xyz";
for(int i = 0; i < s.length(); i++)
{
   char c = s.charAt(i);
}

 


7
ОП очікує вдихання для циклу.
AmitG

3
Даун проголосував, оскільки конкретно це не те, про що вимагала ОП. Хоча це правильне рішення, це зовсім не те, що просять
Сирени

1
Незалежно від того, що очікувала ОП, це має кращі показники, ніж для кожного, що я здогадуюсь.
Ерік Ван

9

Ще одне корисне рішення - ви можете працювати з цим рядком як масивом String

for (String s : "xyz".split("")) {
    System.out.println(s);
}

Елегантний, але, на жаль, він не працює, якщо будь-які елементи рядка split()відображають більше ніж один символ Java, що стосується майже всіх смайликів. Наприклад, цей варіант вашого прикладу буде циклічно чотири рази, а не три:for (String s : "x😁z".split("")) { System.out.println(s); }
skomisa

5

Вам потрібно перетворити об'єкт String в масив char за допомогою toCharArrayметоду () класу String:

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);
}

4

У Java 8 ми можемо вирішити це як:

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

Метод chars () повертає, IntStreamяк зазначено в doc :

Повертає потік int, що розширює значення char із цієї послідовності. Будь-яка таблиця, яка відображається в сурогатній кодовій точці, передається через неінтерпретоване. Якщо послідовність мутується під час читання потоку, результат не визначений.

Навіщо використовувати forEachOrderedі ніforEach ?

Поведінка forEachявно недетерміновано там, де forEachOrderedвиконується дія для кожного елемента цього потоку, в порядку зустрічі потоку, якщо потік має визначений порядок зустрічі. Тож forEachне гарантує, що порядок буде дотримано. Також перевірте це питання для отримання додаткової інформації.

Ми також можемо використовувати codePoints()для друку, для отримання детальної інформації дивіться цю відповідь .


Це створює кілька об'єктів, тому ця відповідь не є повною без застереження, що це може бути менш ефективно, ніж простий індексований цикл.
toolforger

4

На жаль, Java не Stringреалізує Iterable<Character>. Це можна було легко зробити. Є, StringCharacterIteratorале це навіть не реалізується Iterator... Тож зробіть своє:

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++);
            }
        };
    }
}

Тепер ви можете (дещо) легко запустити for (char c : new CharSequenceCharacterIterable("xyz"))...


3

Якщо ви використовуєте Java 8, ви можете використовувати chars()на , Stringщоб отримати Streamсимволи, але вам потрібно буде кинути intназад в charякості chars()повертає IntStream.

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

Якщо ви використовуєте Java 8 з колекціями Eclipse , ви можете використовувати метод CharAdapterкласу forEachз лямбда-методом або посиланням на метод ітерації для всіх символів у String.

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

Цей конкретний приклад також може використовувати посилання на метод.

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

Примітка. Я є членом колекції Eclipse.


1

Ви також можете використовувати лямбда в цьому випадку.

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

-7

Для Travers a String ви також можете використовувати charAt() рядок.

подібно до :

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() це метод обробки обробних рядків в java, який допомагає відстежувати рядок для конкретного символу.


2
ти знаєш, що for (char st: "xyz".toCharArray()) {}таке?
AmitG

Це не складеться.
Maroun

-1 поза темою (тема: для кожного), а використовуйте charAt замість charAT
peenut
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.