10

I have read that Java is pass-by-value, and I've been reading about it in this question at StackOverflow, but I'm still a bit confused, regarding the close() or shutdown() methods in various classes.

What I want to know is, suppose that I do this:

public Constructor(){

    if(isProceeding){
        InputStream iStream = new InputStream();
        processStuff(iStream);
    }
}


public void processStuff(InputStream stream){
    //do stuff
    stream.close();
}

Does the iStream variable actually get closed in processStuff() method or a copy of it gets closed and iStream itself is still left open?

2 Answers 2

15

Objects that are passed around to other methods can be changed by the method, and the caller will notice the change. If you let someone else use your Stream, they might close it and you'd never notice until you try to write and fail. That's why it's usually a good idea not to pass mutable objects around outside your control.

Confusion often arises because many textbooks categorically say "Java has pass-by-value semantics". That is technically true, but not very helpful for a language learner. Technically, it's not the object that gets passed around but a reference to an object, and the called method gets a copy of the reference, which of course references the same object.

But in practice, the difference between object and object reference is often not clear in people's minds. Nobody is ever interested in the value of a reference other than to check whether or not it is null. In fact, Java doesn't even have a dereferencing syntax apart from the member selector .. What people care about is the state of the underlying object. So effectively this means that mutable objects are passed by reference in the sense that the caller gets to change them, and you might be affected by that. In this sense, the textbook explanation is correct and useful for primitive types, but correct and misleading for object types.

1
  • I see, thanks, that clears up my question just right.
    – Raestloz
    Commented Jul 18, 2014 at 2:36
2

In your example, iStream actually gets closed in processStuff(), not a copy. I would recommend, however, always closing the InputStream in the same method where you created it, otherwise it's difficult to understand whether it is closed or not. The call to close() should be in a finally { ... } clause so that for sure it is called, even if an exception is thrown, like this:

package org.company;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Test1 {

    private boolean isProceeding;

    public Test1() {
    }

    public void init(String str) throws IOException {
        if(isProceeding){
            InputStream iStream = null;
            try {
                iStream = new ByteArrayInputStream(str.getBytes("UTF-8"));
                processStuff(iStream);

            } finally {
                iStream.close();
            }
        }
    }

    public void processStuff(InputStream stream){
        //do stuff
    }

    public boolean isProceeding() {
        return isProceeding;
    }

    public void setProceeding(boolean isProceeding) {
        this.isProceeding = isProceeding;
    }

}
2
  • I do think that it's odd to do that, but y'know, I inherited some old code, and mostly the streams are not even closed (!!!), I'm trying to plug the holes here and were confused as to whether what I did actually takes effect or not
    – Raestloz
    Commented Jul 18, 2014 at 2:37
  • Note that from Java 7, you can use the try-with-resources construct (docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html), so that you don't even have to call close() explicitly. Commented Jul 18, 2014 at 5:51

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.