Заведомо верный EQUALS возвращает FALSE, почему так происходит?
Задача: есть строка, нужно изъять из неё (строки) все слова, начинающиеся на "a" и поместить в массив.
Как я решил поступить:
- Заменить все знаки препинания, символы на пустоту и двойные пробелы
на один пробел, чтобы я мог использовать
.split()
- Собственно использовал
.split(" ")
и сразу помещал его результат в ArrayList - Затем я хотел перебрать эту коллекцию и нужные печатать, а ненужные — удалять, но наткнулся на исключение:
Exception in thread "main" java.util.ConcurrentModificationException
(в будущем понял, что мог только удалять, и ошибки бы не было, но я уже хочу решить другим способом)
- Погуглил --> наткнулся на
Iterator
и теперь хочу решить именно через него для лучшего пониманияJava
- Создал
Iterator
на основеArrayList
— далее хочу черезwhile
перебрать итератор и, если первый символ"a"
, то печатать слово — иначе удаляю слово из итератора.
Но тут и начинаются проблемы:
if ("a".equals(String.valueOf(a.charAt(0)))) {
, где a
это:
String a = String.valueOf(iterator.next());
возвращает false
, хз почему...
При этом я затем решил вывести вслед за этим циклов все элементы итератора, и у меня не вывелось ни одного, что, в принципе, логично, так как условие возвратило ложь, и всё поудалялось, но затем я по приколу ввёл индекс не 0, а 1, и у меня вывелись все слова итератора на 1
цикле, но на 2
цикле у меня всё так же не вывелось ни одного слова, как будто в предыдущем цикле их всех удалило, чего не могло быть, так как выполнилась правда.
import java.util.Arrays;
import java.util.Iterator;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
test1();
}
public static void test1() {
String text = "aajiwi aiwefhfhwe wagw, gerhbdf - aiwrhgwbdb wfgw. Drgbibv awhgbwwb: gfuihwergb rg ywrgyf.";
text = text.replaceAll("[,^%$#@!^:;'/\"&*()?><\\-.]", "").replaceAll(" ", " ");
ArrayList<String> res = new ArrayList<>();
res.add(Arrays.toString(text.split(" ")));
System.out.println(res); // Задача из строки изъять все слова начинающиеся с "a" и поместить в массив
Iterator iterator = res.iterator();
while (iterator.hasNext()) {
String a = String.valueOf(iterator.next());
if ("a".equals(String.valueOf(a.charAt(0)))) {
System.out.println(a);
} else {
iterator.remove();
}
}
while (iterator.hasNext()) {
System.out.println("AAAAAAAAA chto za fygniya");
}
}
}
Вывод, если индекс 0:
[[aajiwi, aiwefhfhwe, wagw, gerhbdf, aiwrhgwbdb, wfgw, Drgbibv, awhgbwwb, gfuihwergb, rg, ywrgyf]]
Process finished with exit code 0
Вывод, если индекс 1:
[[aajiwi, aiwefhfhwe, wagw, gerhbdf, aiwrhgwbdb, wfgw, Drgbibv, awhgbwwb, gfuihwergb, rg, ywrgyf]]
[aajiwi, aiwefhfhwe, wagw, gerhbdf, aiwrhgwbdb, wfgw, Drgbibv, awhgbwwb, gfuihwergb, rg, ywrgyf]
Process finished with exit code 0
Почему if
возвращает ложь?
Ответы (2 шт):
Чтобы добавить массив строк в список нужно использовать:
res.addAll(List.of(text.split(" ")));
Вам следует запустить вашу программу в пошаговом отладочном режиме, чтобы убедиться, что она выполняет совершенно не то, что ожидается, но именно то, что было закодировано.
Главная проблема в представленном коде в строке:
res.add(Arrays.toString(text.split(" ")));
System.out.println(res);
// [[aajiwi, aiwefhfhwe, wagw, gerhbdf, aiwrhgwbdb, wfgw, Drgbibv, awhgbwwb, gfuihwergb, rg, ywrgyf]]
так как она записывает в список res
одну-единственную строку как результат вызова Arrays.toString(text.split(" "))
, то есть строковое представление массива строк целиком:
"[aajiwi, aiwefhfhwe, wagw, gerhbdf, aiwrhgwbdb, wfgw, Drgbibv, awhgbwwb, gfuihwergb, rg, ywrgyf]"
Разумеется, первым символом такой строки является '['
, а вторым 'a'
, и в дальнейшем итератор по списку res
обработает только эту единственную строку.
Поэтому прежде всего следует корректно записать массив строк в список res
, например, посредством метода Collections::addAll(Collection<? super T> c, T ... elements)
:
ArrayList<String> res = new ArrayList<>();
Collections.addAll(res, text.split(" "));
или же использовать метод Arrays.asList
:
List<String> res = new ArrayList<>(Arrays.asList(text.split(" ")));
И после этого следует переписать часть с итератором: сделать его типизированным, убрать ненужные преобразования в строки при проверке первого символа, использовать String::startsWith
Iterator<String> iterator = res.iterator();
while (iterator.hasNext()) {
String word = iterator.next();
if (word.startsWith("a")) {
System.out.println(word);
} else {
iterator.remove();
}
}
System.out.println(res); // [aajiwi, aiwefhfhwe, aiwrhgwbdb, awhgbwwb]
И если нужно всё-таки в результате получить массив слов как указано в условии задачи, то придётся преобразовать полученный список res
:
String[] result = res.toArray(new String[0]);
Также следует отметить, что повторный цикл по итератору с паническим сообщением:
while (iterator.hasNext()) { System.out.println("УЖОС!");}
не имеет смысла сам по себе, так как итератор завершил работу в предыдущем цикле, но если бы вдруг было иначе, то этот цикл был бы бесконечным.
Возможные альтернативные способы решения основной задачи:
- С использованием регулярного выражения для поиска слов в строке
Matcher::find
:
Pattern startWithA = Pattern.compile("\\ba\\p{L}*");
List<String> res = new ArrayList<>();
Matcher matcher = startWithA.matcher(text);
while (matcher.find()) {
res.add(matcher.group());
}
где \\ba\\p{L}*
описывает следующий формат слова: граница слова \\b
, первая буква слова английская a
, после которой идут 0 или более других букв \\p{L}*
- С использованием Stream API и улучшенного регулярного выражения для разбиения слов
text.split("\\P{L}+")
-- разделителями являются 1 и более любых небуквенных символов:
String[] result = Arrays.stream(text.split("\\P{L}+"))
.filter(w -> w.startsWith("a"))
.toArray(String[]::new);