执行操作的最佳时间:循环内或循环后

时间:2012-07-28 17:11:19

标签: java performance optimization

我正在阅读稍后要解析的文件。该文件的大小不可能超过MB,因此在这个阶段对我来说这可能不是一个至关重要的问题。但出于最佳实践原因,我想知道何时是执行手术的最佳时间。

示例:

使用我从http://www.dzone.com/snippets/java-read-file-string粘贴的方法,我正在将缓冲区读入字符串。我现在想要删除所有空格。我的方法目前是这样的:

private String listRaw;

public boolean readList(String filePath) throws java.io.IOException {
    StringBuffer fileData = new StringBuffer(1024);
    BufferedReader reader = new BufferedReader(
            new FileReader(filePath));
    char[] buf = new char[1024];
    int numRead=0;
    while((numRead=reader.read(buf)) != -1){
        String readData = String.valueOf(buf, 0, numRead);
        fileData.append(readData);
        buf = new char[1024];
    }
    reader.close();
    listRaw = fileData.toString().replaceAll("\\s","");
    return true;
}

因此,我将字符串中的所有空格从其存储中删除 - 完整地 - 转换为类变量。

对我来说,这意味着处理更少但内存使用量更多。出于最佳做法原因,我将replaceAll()操作添加到readData变量,我会更好地将其附加到fileData吗?使用更多处理但避免传递多余的空白。

我认为这对我正在处理的小文件影响不小,但是如果它是200MB的日志文件呢?

它完全取决于案例,还是有共识我会更好地遵循?


感谢所有人的投入。我相信你已经帮助我的思维方向成为了编写Java的正确方向。

我已更新我的代码以考虑提出的要点。包括Don Roby的建议,在某些时候,我可能想要保留空间。希望事情现在好多了!

private String listRaw;

public boolean readList(String filePath) throws java.io.IOException {
    StringBuilder fileData = new StringBuilder(51200);
    BufferedReader reader = new BufferedReader(new FileReader(filePath));
    char[] buf = new char[51200];
    boolean spaced = false;
    while(reader.read(buf) != -1){
        for(int i=0;i<buf.length;i++) {
            char c = buf[i];
            if (c != '\t' && c != '\r' && c != '\n') {
                if (c == ' ') {
                    if (spaced) {
                        continue;
                    }
                    spaced = true;
                } else {
                    spaced = false;
                }

                fileData.append(c);
            }
        }
    }
    reader.close();
    listRaw = fileData.toString().trim();
    return true;
}

3 个答案:

答案 0 :(得分:7)

最后,您最好只创建和应用一次regexp替换。但是你可以通过

获得更多
  • 使用合理的大小初始化StringBuilder
  • 避免在循环内创建String,并将读取的字符直接附加到StringBuilder
  • 避免在每次迭代时实例化新的char缓冲区。

为了避免不必要的长临时字符串创建,您可以通过char读取char,并且仅将char添加到StringBuilder not a whitespace。最后,StringBuilder只包含好的字符,您不需要任何replaceAll()调用。

答案 1 :(得分:4)

在这段代码中,实际上有几个非常显着的低效率,你必须先修复它们,然后再担心你提出的相对不那么重要的问题。

首先,不要在循环的每次迭代中创建一个新的buf对象 - 使用相同的对象!这样做没有问题 - 新数据会覆盖旧数据,并节省对象分配(这是您可以执行的更昂贵的操作之一。)

其次,同样地,不要创建String来调用append() - 使用append形式的char数组和偏移量(0,在这种情况下)和长度(numRead,在这种情况下。)同样,每循环迭代创建一个较少的对象。

最后,回答你实际问过的问题:在循环中执行它会在每次迭代时创建一个String对象,但是通过我们刚刚完成的调整,你创建了对象每次迭代 - 所以删除循环结束时的空白是明显的赢家!

答案 2 :(得分:1)

在某种程度上取决于你要做的解析,你可能会更好地取消而不是在一个单独的步骤中删除空格,并在解析过程中忽略它们。

想要删除所有空白也是非常罕见的。您确定不想用单个空格替换多个空格吗?