skip to Main Content

If I initialize String array directly like this String[] Distro = Distros.split(","); then it’ll create an object because variable Distro is holding the array.

But If I do it this way then it’ll also create an object?

        String Distros = "CentOS,RHEL,Debian,Ubuntu";

        for (String s : Distros.split(",")) {
            System.out.println(s);
        }

My goal is to reduce object creation to minimize garbage.

2

Answers


  1. The method split(delimiter) returns string array from the string based on the delimiter, what you did create the string array in for each and the scope of it ended after for each so It’s eligible for GC to release it

        String Distros = "CentOS,RHEL,Debian,Ubuntu";
        for (String s : Distros.split(",")) {
            System.out.println(s);
        }
    

    , Is equivalent to

        String Distros = "CentOS,RHEL,Debian,Ubuntu";
    
        System.out.println("start scope");
        {
          String[] splitArray = Distros.split(",");
          for (String s : splitArray) {
            System.out.println(s);
          }
        }
        System.out.println("end scope");
    
    Login or Signup to reply.
  2. Your reasoning “then it’ll create an object because variable Distro is holding the array” indicates that you are confusing object creation with variable assignment.

    The object is created by the expression Distros.split(","), not the subsequent assignment. It should become obvious when you consider that the split method is an ordinary Java method creating and returning the array without any knowledge about what the caller will do with the result.

    When the operation happens in a performance critical code, you might use

    int p = 0;
    for(int e; (e = Distros.indexOf(',', p)) >= 0; p = e+1)
        System.out.println(Distros.substring(p, e));
    System.out.println(Distros.substring(p));
    

    instead. It’s worth pointing out that this saves the array creation but still performs the creation of the substrings, which is the more expensive aspect of it. Without knowing what you are actually going to do with the substrings, it’s impossible to say whether there are alternatives which can save the substring creation¹.

    But this loop still has an advantage over the split method. The split method creates all substrings and returns an array holding references to them, forcing them to exist at the same time, during the entire loop. The loop above calls substring when needed and doesn’t keep a reference when going to the next. Hence, the strings are not forced to exist all the time and the garbage collector is free to decide when to collect them, depending on the current memory utilization.


    ¹ I assume that printing is just an example. But to stay at the example, you could replace

        System.out.println(Distros.substring(p, e));
    

    with

        System.out.append(Distros, p, e).println();
    

    The problem is, this only hides the substring creation, at least in the reference implementation which will eventually perform the substring creation behind the scenes.

    An alternative is

    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                            new FileOutputStream(FileDescriptor.out)));
    try {
        int p = 0; for(int e; (e = Distros.indexOf(',', p)) >= 0; p = e+1) {
            bw.write(Distros, p, e - p);
            bw.write(System.lineSeparator());
        }
        bw.write(Distros, p, Distros.length() - p);
        bw.write(System.lineSeparator());
        bw.flush();
    }
    catch(IOException ex) {
        ex.printStackTrace();
    }
    

    which truly writes the strings without creating substrings. But it forces us to deal with potential exceptions, which PrintStream normally hides.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search