我有一个LogAnalyzer类,它查看Web服务器日志,创建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);
}
答案 0 :(得分:1)
从构造函数内部调用方法不是一个好习惯,因为Java总是调用派生程度最高的方法,这意味着我们可以在半初始化对象上调用方法。
要回答您的问题,
public LogAnalyzer() {
records = new ArrayList<>();
dailyRecords = new HashMap<>();
uniqueIPs = new HashMap<>();
}
以上部分的确切作用是,它为变量,记录,dailyRecods和uniqueIPs提供了内存堆栈中的物理地址。
当我们在类中编写类似private ArrayList<LogEntry> records;
的内容时,此时仅生成一个引用,但是实际的初始化仅在records = new ArrayList<>();
该行被执行时发生。
希望这可以澄清您的疑问!
答案 1 :(得分:1)
如您在dailyRecords.keySet().contains(date)
中所见,它使用以下指令
dailyRecords
,而不先初始化dailyRecords
。因此,如果您在声明时或在构造函数中未初始化NullPointerException
,您将面临private HashMap<String, ArrayList<LogEntry>> dailyRecords = new HashMap<>();
。
在这种情况下,您可以使用声明部分,而不是使用构造函数进行初始化
post_build
答案 2 :(得分:1)
保留这两种方法可以使您在使用代码时更具灵活性。您可以在不知道日志路径的情况下实例化LogAnalyzer。我将initializeRecords
重命名为processRecords
,这对IMO更具描述性。
我们应该先创建对象,然后在其上调用方法。如果您的readFile
方法因为无法读取文件而抛出异常。我在构造对象时发现该异常非常奇怪。构造函数的重点是提供一个可用于执行某些操作的对象。