Java: стратегия ограничения области видимости переменной - PullRequest
1 голос
/ 05 июля 2019

Я просто наткнулся на ошибку и спрашиваю себя, есть ли лучший способ сделать это.

Сначала у меня был этот код.

// 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 (строку) вместо 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 ]

4 голосов
/ 05 июля 2019

То, что вы ищете, имеет чистую функцию [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
 }
}

В вашем основном методе вы будете вызывать обе функции следующим образом:

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

Кроме того, должен быть модульный тест для обеих функций.

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

2 голосов
/ 05 июля 2019

Это всего лишь предложение, и оно работает только при использовании ресурсов, но в вашем случае вы можете

  1. избавиться от br.close() и
  2. ограничивает область, в которой line объявляется только с использованием подхода 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
}

В соответствии с рекомендациями, я проигнорировал тот факт, что ваш вопрос не требует реальной оптимизации.

1 голос
/ 05 июля 2019

Другое решение, характерное для вашего примера кода: вы можете объявить переменные в операторе инициализации цикла for, который будет доступен только в теле цикла.

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

Каждый цикл while можно преобразовать вfor, но результирующий цикл часто может сбивать с толку, поэтому комментируйте обильно.

1 голос
/ 05 июля 2019

Неясно, хотите ли вы получить доступ к строковой переменной после заполнения списка, но если вы этого не сделаете, вы можете полностью удалить ее.

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

for (String s : lst) {
  foo(line);   // error now
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...