有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在Java中,在一个循环中多次实例化一个对象是一种不好的做法吗?

我正在处理一个Java项目,一个变量在while循环中反复实例化为局部变量

while ((inputLine = in.readLine()) != null){
    Matcher matcher = pattern.matcher(inputLine);
    isFound = matcher.find();
    if(isFound){
      break;
    }
}

问题是,局部变量匹配器每次都在while循环中实例化,直到循环终止

我在想,这会不会减慢处理时间


共 (5) 个答案

  1. # 1 楼答案

    一般来说,没有。通常情况下,你需要这样做。当然,您确实希望避免虚假和过多的堆栈分配,因为它们不是免费的,但是在许多非常好的情况下,您需要在循环中创建一个对象

    实例化和声明之间也有区别。在您的示例中,pattern.matcher(inputLine)是您的对象实例化;你只是用这句话创建了一个新的匹配器Matcher matcher = ...是您的声明。如果您询问是否可以在循环中多次声明变量,这同样取决于上下文。通常,这很好,事实上比在循环外部声明变量更可取,因为匹配器的每个实例的范围(大概)都应该限制在循环的单个迭代中。这个作用域机制可以帮助您避免以后在应用程序中产生bug

  2. # 2 楼答案

    视情况而定

    在这种特殊情况下,可以这样做。这是因为inputLine在循环的每次迭代中都在变化。如果不在每次迭代中创建一个新的Matcher,您就无法做到这一点。另外,Matcher的构造函数似乎就是这样做的:

    Matcher(Pattern parent, CharSequence text) {
        this.parentPattern = parent;
        this.text = text;
    
        // Allocate state storage
        int parentGroupCount = Math.max(parent.capturingGroupCount, 10);
        groups = new int[parentGroupCount * 2];
        locals = new int[parent.localCount];
    
        // Put fields into initial states
        reset();
    }
    

    我不会说那是很多

    在其他可以避免创建实例的情况下,应避免创建实例。循环中的字符串串联就是一个很好的例子

    例如:

    String s = "";
    for(int i = 0 ; i < 100 ; i++) {
        s += Integer.toString(i); // string is immutable so this creates a new string every time.
    }
    

    您应该使用StringBuilder

  3. # 3 楼答案

    视情况而定。对于这个特殊的案例,其他人已经回答了你的问题。一般来说,在循环中实例化一个对象,以便在年轻一代的集合中对其进行清理,通常(但并非总是)效果更好。Java的GC针对短期对象进行了优化

    变量的范围需要符合情况的逻辑,而不是关于“更好”的教条。对象可能比变量更长寿,例如在循环中:

    Result result = null;
    for (int ix = 0; ix < limit; ++ix) {
      Result candidate = new Result();
      if (condition()) {
        result = candidate;
        break;
      }
    }
    if (result != null) { ...
    

    这里,candidate变量在循环之后超出范围。如果指定了一个非null值,则result变量将指向超出其原始引用的对象。所有其他候选人都有资格获得GC。(这个例子是精心设计的,但旨在说明这一点。)

    例外情况是当初始化开销很大,并且在循环内不重复时。如果对象的构造是巨大的,并且循环只改变对象状态的一些小部分而不重复大量的工作,那么您可以考虑在循环之外创建对象。p>

    “大规模”有多大?很难知道。但对象创建几乎是免费的,年轻一代GC也几乎是免费的。死对象不会增加年轻的GC开销。当对象处于长期状态时,GC开销会增加,所以您希望保持生命周期尽可能短

    生命周期管理是Java编程的黑暗艺术之一。不过,如果你喜欢尽快扔掉东西,你基本上不会出错。要偏离这一经验法则,您必须衡量不同生命周期策略之间的差异。在某些情况下,将对象保留更长的时间可以显著提高性能,但如果您对其进行研究,您会发现结果是通过大量实验和精确的度量来实现的

  4. # 4 楼答案

    在我看来,您使用Matcher对象的方式应该在循环外部实例化,然后使用它

  5. # 5 楼答案

    在Java here中进行模式匹配的标准模式是:

    1. 实例化模式
    2. 对于要测试的每个输入字符串s,创建一个匹配器m via。匹配,就像你正在做的一样
    3. 通过Matcher中的m.matches()/find()方法测试匹配,就像您正在做的那样