Много реализаций классов платформы Java Iterable
, однако String
не делает. Имеет смысл выполнять итерации по символам в a String
, так же, как можно выполнить итерации по объектам в эквидистантной антенной решетке.
Есть ли причина почему String
не реализует Iterable
?
На самом деле хорошего ответа нет. Итератор в Java применяется конкретно к коллекции дискретных элементов (объектов). Можно подумать, что String
, который реализует CharSequence
, должен быть "коллекцией" дискретных символов. Вместо этого она рассматривается как единое целое, состоящее из символов.
В Java кажется, что итераторы действительно применяются только к коллекциям, но не к строке. Нет никаких причин, почему это так (насколько я могу судить - вам, вероятно, придется поговорить с Гослингом или авторами API); похоже, что это условность или дизайнерское решение. Действительно, ничто не мешает CharSequence
реализовать Iterable
.
Учитывая это, вы можете перебирать символы в строке следующим образом:
for (int i = 0; i < str.length(); i++) {
System.out.println(str.charAt(i));
}
Or:
for(char c : str.toCharArray()) {
System.out.println(c);
}
Or:
"Java 8".chars().forEach(System.out::println);
Также обратите внимание, что вы не можете изменить символ строки на месте, поскольку строки неизменяемы. Мутабельным компаньоном строки является StringBuilder (или более старый StringBuffer).
EDIT
Чтобы уточнить, основываясь на комментариях к этому ответу. Я пытаюсь объяснить возможное обоснование того, почему не существует итератора для String
. Я не пытаюсь сказать, что это невозможно; действительно, я думаю, что было бы логично для CharSequence
реализовать Iterable
.
String
предоставляет CharSequence
, который, хотя бы концептуально, отличается от String
. Строка String
обычно рассматривается как единое целое, тогда как CharSequence
является именно этим: последовательностью символов. Имеет смысл иметь итератор на последовательности символов (т.е. на CharSequence
), но не просто на самой String
.
Как справедливо заметил Foxfire в комментариях, String
реализует интерфейс CharSequence
, поэтому с точки зрения типов, String
является CharSequence
. Семантически, мне кажется, что это две разные вещи - возможно, я педантичен, но когда я думаю о String
, я обычно думаю о ней как о едином объекте, который состоит из символов. Рассмотрим разницу между последовательностью цифр 1, 2, 3, 4
и числом 1234
. Теперь рассмотрим разницу между строкой abcd
и последовательностью символов a, b, c, d
. Я пытаюсь указать на эту разницу.
На мой взгляд, спрашивать, почему у String
нет итератора, все равно что спрашивать, почему у Integer
нет итератора, чтобы можно было перебирать отдельные цифры.
Причина проста: строковый класс намного старше, чем Iterable.
И, очевидно, никто никогда не хотел добавлять интерфейс к String (что несколько странно, потому что он действительно реализует CharSequence, основанный на точно такой же идее).
Однако это было бы несколько несовершенным, потому что Iterable возвращает объект . Так что нужно было бы обернуть каждый возвращенный Char.
Редактировать: Так же, как сравнение: .Net поддерживает перечисление в String, однако в .Net Iterable также работает с собственными типами, поэтому нет необходимости в переносе, как это требовалось бы в Java.
Если вы действительно заинтересованы в итерации, вот:
String str = "StackOverflow";
for (char c: str.toCharArray()){
//here you go
}
Мой коллега Джош Блох очень хочет добавить эту функцию в Java 7:
for (char c: aString) {.. .}
и
for (int codePoint: aString) {...}
Это был бы самый простой способ перебрать символы и логические символы (кодовые точки) в цикле. Это не потребовало бы реализации String
реализации Iterable
, что привело бы к блокировке.
Без этой языковой особенности не было бы действительно хорошего ответа на эту проблему. И он кажется очень оптимистичным, что сможет добиться этого, но я не уверен.
Iterable
чего? Iterable
имеет наибольший смысл, если каждый элемент представляет кодовую точку Unicode. Даже Iterable
будет медленным и бессмысленным, если у нас есть toCharArray
.
Одна из основных причин, по которой String реализует Iterable, - это включение простого цикла for (each), как упоминалось выше. Итак, причиной того, что String не реализует Iterable, может быть внутренняя неэффективность наивной реализации, поскольку она требует упаковки результата. Однако, если реализация итогового Iterator (возвращаемого String.iterator ()) является окончательной, компилятор может обработать его в особом случае и сгенерировать байт-код, свободный от упаковки / распаковки.