Java:限制变量范围的策略

时间:2019-07-05 14:18:33

标签: java

我只是偶然发现一个错误,问自己是否有更好的方法来做。

首先我有这段代码。

// read lines out of a file and do something with it in foo
BufferedReader br = new BufferedReader (new FileReader ("bla.txt")); 
String line; 
while ((line = br.readLine ()) != null) 
{
  foo (line);
}
br.close ();

然后我更改了它。引入了一个列表,而不是在读取循环中工作。

BufferedReader br = new BufferedReader (new FileReader ("bla.txt")); 
List <String> lst = new ArrayList <String> ();
String line; 
while ((line = br.readLine ()) != null) 
{
  lst.add (line);
}
br.close ();
for (String s : lst)
{
  foo (line);   // !!!
}

请忽略以下事实:这不是真正的优化。该代码只是我的问题的简化。

在使用收藏集时,我犯了一个错误。我确实将foo(line)替换为foo(s)。 那不是编译器错误,但是我的算法是错误的。

如果不更模块化(使用功能等),避免这种问题的一个好策略是什么?

我想通过将其放在一个块中来限制行的范围。

BufferedReader br = new BufferedReader (new FileReader ("bla.txt")); 
List <String> lst = new ArrayList <String> ();

{
  String line; 
  while ((line = br.readLine ()) != null) 
  {
    lst.add (line);
  }
  br.close ();
}

for (String s : lst)
{
  foo (line);   // error now
}

但是我不确定这是一个通用且好的策略。对这种问题有什么建议吗?谢谢!

4 个答案:

答案 0 :(得分:4)

您要寻找的是具有纯函数[1]。为了实现这一点,您应该具有两个单独的功能,一个用于读取内容,另一个用于处理内容。第二个函数应将参数作为列表。如下所示:

List<String> readContent(){ 
   BufferedReader br = new BufferedReader (new FileReader ("bla.txt")); 
   List <String> lst = new ArrayList <String> ();

   {
     String line; 
     while ((line = br.readLine ()) != null) 
     {
       lst.add (line);
      }
    br.close ();
   }
   return lst;
}

void processContent(List<String> contentList){
 for (String s : contentList){
  foo (s);   // error now
 }
}

在您的main方法中,您将调用以下两个函数:

List<String> contents = readContent();
processContent(contents);

此外,这两个功能也都应该进行单元测试。

[1] https://en.wikipedia.org/wiki/Pure_function

答案 1 :(得分:2)

这只是一个建议,它仅在使用资源时有效,但对于您而言,您可以

  1. 摆脱br.close()
  2. 仅使用line-with-resource方法来限制声明try的范围。

看看下面的代码:

public static void main(String[] args) {
    List <String> lst = new ArrayList <String> ();

    // specifically try the BufferedReader, it will get closed in every case
    try (BufferedReader br = new BufferedReader(new FileReader("bla.txt"))) {
        String line;
        while ((line = br.readLine()) != null) {
            lst.add(line);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    lst.forEach(s -> System.out.println(s)); // Java 8 for-each
}

根据建议,我忽略了您的问题并不需要真正优化的事实。

答案 2 :(得分:1)

目前尚不清楚是否要在填充列表之后访问line变量,但是如果不想,则可以将其完全删除。

List<String> lst = new ArrayList<>(Files.readAllLines(Paths.get("bla.txt")));

for (String s : lst) {
  foo(line);   // error now
}

答案 3 :(得分:1)

另一个针对示例代码的解决方案:您可以在for循环的初始化语句中声明变量,该变量只能在循环的主体中访问。

for (String line=br.readLine(); line != null ; line = br.readLine()) {
    //line is accessible
}
// line is undeclared

每个while循环都可以转换为for循环,但是产生的循环通常可能令人困惑,因此请多加注释。