Инициализация пустых переменных экземпляра в конструкторе - PullRequest
0 голосов
/ 16 января 2020

У меня есть класс LogAnalyzer, который просматривает журнал веб-сервера, создает объекты LogEntry и помещает эти объекты в HashMaps для анализа.

Мой класс LogAnalyzer имеет следующие поля:

private int totalVisits;
private int uniqueVisits;
private ArrayList<LogEntry> records;
private HashMap<String, ArrayList<LogEntry>> uniqueIPs; //<address, log entries>
private HashMap<String, ArrayList<LogEntry>> dailyRecords; // <date, log entries>

Мой конструктор выглядит так:

public LogAnalyzer() {

    records = new ArrayList<>();
    dailyRecords = new HashMap<>();
    uniqueIPs  = new HashMap<>();

}

И тогда у меня есть этот метод:

public void initializeRecords(String path){
    readFile(path); //reads the web log file and fills out the records and dailyRecords fields
    getUniqueIPs(); //fills out the uniqueIPs HashMap field.
    uniqueVisits = uniqueIPs.size(); //fills out the uniqueVisits field
    totalVisits = records.size(); //fills out the totalVisits field
}

Итак, мой вопрос:

Я прочитал (но на самом деле не понимаю), что "плохо" вызывать методы внутри конструктора. Однако кажется, что конструктор здесь не имеет смысла, так как на самом деле initializeRecords выполняет всю значимую работу по «созданию» объекта.

У меня нет опыта в Java или программирования, чтобы понять объяснения, которые я нашел до сих пор. Есть много разговоров о первостепенных вещах, и я думаю, что это то, что мне не ясно. Мне интересно, почему я должен держать свой конструктор и этот метод разделенными, в простых терминах, которые может понять новичок.

** РЕДАКТИРОВАТЬ: ** Вот код для readFile ():

public void readFile(String filename) {
    FileResource fr = new FileResource(filename);
    for (String line : fr.lines()){
        LogEntry le = WebLogParser.parseEntry(line);
        String date = le.getAccessTime().toString().substring(4, 10);
        if (dailyRecords.keySet().contains(date)){
            dailyRecords.get(date).add(le);
        }
        else{
            ArrayList<LogEntry> entries = new ArrayList<>();
            entries.add(le);
            dailyRecords.put(date, entries);
        }
        records.add(le); 
    }

Ответы [ 3 ]

1 голос
/ 16 января 2020

Как вы можете видеть в readFile(), он использует следующую инструкцию

dailyRecords.keySet().contains(date)

без инициализации dailyRecords до этого. Поэтому, если вы не инициализируете dailyRecords ни при объявлении, ни в конструкторе, вы столкнетесь с NullPointerException.

В вашем случае вместо использования конструктора для инициализации вы можете использовать часть объявления, такую ​​как

private HashMap<String, ArrayList<LogEntry>> dailyRecords = new HashMap<>();    
1 голос
/ 16 января 2020

Сохранение двух методов позволяет вам более гибко использовать ваш код. Вы можете создать экземпляр LogAnalyzer, не зная пути к вашему журналу. Я бы переименовал initializeRecords в processRecords, что IMO более наглядно описывает, что вы там делаете.

Сначала мы должны создать объект, а затем вызвать для него методы. Если ваш метод readFile должен выдать исключение, потому что он не может прочитать файл, например. Мне было бы очень странно получить это исключение при создании объекта. Задача конструктора - предоставить объект, который можно использовать для чего-либо.

1 голос
/ 16 января 2020

Не рекомендуется вызывать методы из конструктора, поскольку Java всегда вызывает самый производный метод, что означает, что мы можем вызвать метод для полуинициализированного объекта.

Чтобы ответить на ваш вопрос ,

public LogAnalyzer() {

    records = new ArrayList<>();
    dailyRecords = new HashMap<>();
    uniqueIPs  = new HashMap<>();

}

То, что вышеупомянутая часть точно делает, это то, что она дает переменным, записям, dailyRecods и уникальным IP-адресам физический адрес в стеке памяти.

Когда мы пишем что-то вроде private ArrayList<LogEntry> records; в классе, в это время генерируется только ссылка, но фактическая инициализация происходит только тогда, когда records = new ArrayList<>(); выполняется эта строка.

Надеюсь, это прояснит твое сомнение !!!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...