2017-03-01 22 views
0

我正在为学校解决问题。很多这种方法已经实施,我不能做太多的改变。如何更改消费者之外的列表

其实我只能在具体点进行更改。

下面是我正在使用的方法的代码,虽然有些词语是荷兰语,但它应该是可读的。

它应该读取文件的行,从文本中创建地址(保存为(street +“”+ number +“”+ place))并将它们添加到返回的列表中。该文件以空行结束。

@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方法。任何帮助表示赞赏。

+0

尽量使列表'final' :'final ArrayList adressen = new ArrayList <>();'。 – Berger

+0

但是,这不会使列表不可变? – Typhaon

+0

不,这只意味着您以后不能将其他对象分配给'adressen'变量。 – Berger

回答

2

当你与Java7的工作,那么编译器将需要

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

那里。重点是:你想在内使用局部变量一个不喜欢的内部类;换句话说:在与您放置源代码的类别不同的​​上下文中。并且为了解耦类能够使用 adressen需要是最终的(以便编译器知道:该引用稍后将不会改变)。并给出你的评论:不,这不会神奇地将一个对象变成不变的。它只是防止参考更改它指向的“目标”!

但正如你不能改变这条线,你可以去:

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

,然后让你的代码使用tempAdressen。

另外,我假设你正在使用Java7。对于Java8,编译器应该能够理解adressen有效最终;因此它应该按原样接受源代码。

+0

我不知道Java 8能够识别这个问题。那么,好习惯已经在这里,但很好知道。 – AxelH

+0

非常欢迎;-) – GhostCat

0

看来你已经在使用Java8了,因为在BufferedReader中调用了lines()

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

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