如何更改消费者之外的列表

时间:2017-03-01 09:25:50

标签: java list foreach consumer

我正在为学校解决问题。很多这种方法已经实施,我不允许做太多改动。

实际上我只能在特定点进行更改。

这里是我正在研究的方法的代码,虽然有些单词是荷兰语,但它应该是可读的。

它应该读取文件的行,从文本创建地址(保存为(街道+"" +数字+"" +地点))并添加它们到返回的列表。该文件以空行结束。

@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 个答案:

答案 0 :(得分:2)

当您使用Java7时,编译器需要

final ArrayList<Adres> adressen = new ArrayList<>();

那里。关键是:你想在中使用那个局部变量一个非常内在的类;换句话说:在一个与您放置源代码的类以某种方式分离的上下文中。并且为了使解耦类能够使用,adressen需要是最终的(以便编译器知道:该引用稍后不会更改)。并且鉴于你的评论:不,这并没有神奇地将一个对象变成不可变的。它只是阻止引用更改它指向的“目标”!

但由于你不允许改变这一行,你可以选择:

ArrayList<Adres> adressen = new ArrayList<>();
final ArrayList<Adres> tempAdressen = adressen;

然后您的代码使用tempAdressen。

或者,我假设您使用的是Java7。使用Java8,编译器应该能够理解adressen有效的最终;因此它应该按原样接受源代码。

答案 1 :(得分:0)

由于在BufferedReader中调用lines(),您似乎已经在使用Java8。

所以我的建议是做一张地图然后收集列表,而不是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())
);

答案 2 :(得分:0)

使用Java8,您可以使用 java.util.stream.Collectors 直接从流中返回元素列表。使用收集器可以帮助您避免副作用(在您的情况下,需要使用外部数组来解析元素)。

我会亲自使用以下lambda编写它:

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

这将有效,但它不会处理数据格式错误的情况。要解决这个问题,可以通过修改lambda(即使这不是很优雅)来改变上面的代码来处理一行是否由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());