Как изменить список за пределами потребителя
Я работаю над проблемой для школы. Многие из этих методов уже были реализованы, и мне не разрешено вносить слишком много изменений.
На самом деле я могу вносить изменения только в определенных местах.
Вот код метода, над которым я работаю, хотя некоторые слова на нидерландском языке, он должен быть читаемым.
Он должен прочитать строки файла, создать адреса из текста (который сохраняется как (улица +" "+ номер +" "+ место)) и добавить их в список, который возвращается. Файл заканчивается пустой строкой.
@Override
public List<Adres> query(ISpecification specification) {
if (specification instanceof FileSpecification) {
if (((FileSpecification) specification).toFileQuery().equals("ALL")) {
ArrayList<Adres> adressen = new ArrayList<>();
/*---start of my code*/
File studentF = new File(fsConnection.getStudentConnection());
try {
FileReader fr = new FileReader(studentF);
BufferedReader br = new BufferedReader(fr);
br.lines().forEach(new Consumer<String>(){
@Override
public void accept(String line) {
String[] words = line.split("\\s");
if(words.length == 3){
/*line i'm having trouble with*/adressen.add(new Adres(words[0], Integer.parseInt(words[1]), words[2]);
}
}
});
} catch (FileNotFoundException ex) {
Logger.getLogger(AdresFile.class.getName()).log(Level.SEVERE, null, ex);//Don't mind this
}
/*---end of my code*/
//System.out.println("query: Nog niet geimplementeerd!");
return adressen;
} else {
return null;
}
} else {
return null;
}
}
Как видите, я хотел получить доступ к списку за пределами потребительского блока. Теперь я знаю, что это невозможно. Я думал о создании другого метода или около того, но это не разрешено. Я должен использовать метод foreach. Любая помощь приветствуется.
3 ответа
Когда вы работаете с Java7, компилятору потребуется
final ArrayList<Adres> adressen = new ArrayList<>();
там. Дело в том, что вы хотите использовать эту локальную переменную в аномальном внутреннем классе; другими словами: в контексте, который каким-то образом отделен от класса, вы помещаете исходный код. И для того, чтобы разъединенный класс мог использовать adressen, он должен быть окончательным (чтобы компилятор знал: эта ссылка не изменится позже). И учитывая ваш комментарий: нет, это не волшебным образом превращает объект во что-то неизменное. Это просто предотвращает изменение ссылки на "цель", на которую она указывает!
Но так как вы не можете изменить эту строку, вы можете пойти на:
ArrayList<Adres> adressen = new ArrayList<>();
final ArrayList<Adres> tempAdressen = adressen;
а затем ваш код использовать tempAdressen.
В качестве альтернативы, я предполагаю, что вы используете Java7. С Java8 компилятор должен понимать, что adressen
фактически является окончательным; и, таким образом, он должен принять исходный код как есть.
Кажется, вы уже используете Java8 из-за вызова lines()
в BufferedReader.
Поэтому я предлагаю сделать карту, а затем собирать в список вместо forEach. Таким образом, вам не нужно будет получать доступ к списку из вашего потребителя.
adressen.addAll(
br.lines().map(line -> {
String[] words = line.split("\\s");
if (words.length == 3) {
return new Adres(words[0], Integer.parseInt(words[1]), words[2]);
}
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toList())
);
В Java8 вы можете использовать java.util.stream.Collectors для возврата списка элементов непосредственно из потока. Использование коллекторов поможет вам избежать побочных эффектов (в вашем случае необходимо использовать внешний массив для разбора элементов).
Я лично написал бы это, используя следующую лямбду:
List<Adres> adressen = br.lines().stream()
.map(line -> line.split("\\s"))
.filter(words -> words.length == 3)
.map(words -> new Adres(words[0], Integer.parseInt(words[1]), words[2]))
.collect(Collectors.toList());
Это будет работать, но не будет обрабатывать случай, когда данные искажены. Чтобы решить эту проблему, можно изменить приведенный выше код для обработки, если строка не состоит из 3 элементов, изменив лямбду (даже если это не очень элегантно):
List<Adres> adressen = br.lines().stream()
.map(line -> line.split("\\s"))
.filter(words -> {
if (words.length == 3)
return true;
else {
throw new IllegalArgumentException();
}
})
.map(words -> new Adres(words[0], Integer.parseInt(words[1]), words[2]))
.collect(Collectors.toList());