1

First of all, excuse me if my english isn't perfect, but I'm not from a english speaking country (Spain), so...

Well, here's the question. When creating a class, ¿is a good practice to use temporary variables all you can, or is better to declare your variables as class variables, just in order to keep things clear?

I'll give you an example, using a simple class SpriteSheet. Is a very short and popular class, used almost in every 2D game out there in Java.

Here is the code just as it originally was planned by the creator of the tutorial I was watching:

public class SpriteSheet {

private String path;
private final int SIZE;
public int[] spriteSheetPixels;

public SpriteSheet(String path, int size) {
this.path = path;
SIZE = size;

spriteSheetPixels = new int[SIZE * SIZE];

load();
}

private final void load() {
try {
    BufferedImage image = ImageIO.read(SpriteSheet.class
        .getResource(path));
    int w = image.getWidth();
    int h = image.getHeight();
    image.getRGB(0, 0, w, h, spriteSheetPixels, 0, w);
} catch (IOException e) {
    e.printStackTrace();
}
}

}

Point is, he is doing just a normal class, following all Java conventions as far as I know. After having a look at it, I thought I could improve it a little bit. Here is my version of the very same class:

public final class SpriteSheet {

public final int[] spriteSheetPixels;

public SpriteSheet(final String path, final int width, final int height) {
spriteSheetPixels = new int[width * height];

load(path, width, height);
}

private final void load(final String path, final int width, final int height) {
try {
    BufferedImage image = ImageIO.read(SpriteSheet.class
        .getResource(path));

    final int w = image.getWidth();
    final int h = image.getHeight();
    final byte ZERO = 0;

    image.getRGB(ZERO, ZERO, w, h, spriteSheetPixels, ZERO, w);
} catch (IOException e) {
    e.printStackTrace();
}
}

}

Just in case, if you don't feel like paying too much attention, I'll try to resume what I've changed and why: - Added "final" to class declaration, as I don't think I'll ever need to instantiate it. - Removed all class variables except for the array, as it is the only thing I'll end up using from this class. I feel like having the rest of the variables declared as class variables is just a waste of memory. If they're temporary, if I'm not mistaken, they'll be used and then the GC will take care of them sooner or later, freeing memory. - Marked the array as final because it'll stay as it is for the rest of runtime. - Split the SIZE constant into width and height, just in case I decide using some non square sprite sheets. - Declaring w and h is actually a good think, as calling methods in the parameters is usually bad for execution speed (or that's what I've read in some places). - As 0 is used several times, I believe declaring it as a variable will help to improve the execution speed (just a tiny little bit, probably won't be noticeable anyway).

And that's basically all of it. Be aware I'm a studient and probably I'm making some very n00b mistakes, and that's why I wanted to ask here, as I'm sure there are lots of experienced programmers around.

Bare in mind I don't really care about the SpriteSheet class, I'm more curious about the quality of my optimisations.

¿Did I improved things or make them worst (making things actually slower, less readable, harder to maintain in the future, doing things that the compiler will do anyways...)?

Sorry if my question is too long and too vague, is my first one so, easy on me ;)

Thanks in advance.

EDIT:

I just read it after a little break, and it doesn't make any sense (have you seen that I'm parsing width and height parameters to load() and never use them?)

Here is as I believe it should be:

public final class SpriteSheet {

public final int[] spriteSheetPixels;

public SpriteSheet(final String path, final int width, final int height) {
final byte ZERO = 0;
spriteSheetPixels = new int[width * height];

try {
    BufferedImage image = ImageIO.read(SpriteSheet.class
        .getResource(path));

    image.getRGB(ZERO, ZERO, width, height, spriteSheetPixels, ZERO,
        width);
} catch (IOException e) {
    e.printStackTrace();
}
}

}

Just realized I don't need the method really. Everything can be done in the constructor.

  • Class variables define attributes for the object. If you think that a variable is not contributing to attributes for that object, then its better to keep it temporary. It all comes down to how you want to design your class. – ata Mar 30 '14 at 01:52
  • Yes and sometimes, the hardest thing is to know if you're going to actually need those attributes (for example, use them for something accesing from another class). – Best Bloody Day Mar 30 '14 at 02:21

3 Answers3

3

Or is better to declare your variables as class variables, just in order to keep things clear?

I think you mean "attributes" (instance variables), not static (class) variables. Declaring everything as instance variables will make things very very unclear.

Short answer: use local variables and create attributes only if strictly necessary, for data that is shared across different methods. Besides, local variables can be slightly faster to access than attributes.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • The standard language in Stack Overflow is english, but if it helps to make things clearer just know that … aquí también se habla español :) – Óscar López Mar 30 '14 at 01:50
  • Yes, that's what I meant to say, just couldn't translate it properly. Thank you (gracias jeje). By the way, I'll edit the code a tiny bit, as I copied the wrong implementation. – Best Bloody Day Mar 30 '14 at 02:16
  • "Attributes" is not the proper terminology for Java. The [JLS](http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2) uses the term "field." – Mike Samuel Mar 30 '14 at 02:23
  • It's so frustrating @MikeSamuel, all this confusion is because of learning Java in spanish and now trying to explain myself in English. Thank you for the link. – Best Bloody Day Mar 30 '14 at 02:30
  • Don't apologize. Your English is fine. It's we native English speakers who should apologize for never fixing our orthography which resulted from a millennium-long train crash between a Romance language and a Germanic language with Celtic languages heckling from the sidelines. – Mike Samuel Mar 30 '14 at 02:47
0

When creating a class, ¿is a good practice to use temporary variables all you can, or is better to declare your variables as class variables, just in order to keep things clear?

If information is only relevant to the currently running method, then store it in a local variable with as small a scope as possible.

If information about the object needs to outlast any one method call, and it cannot be derived from other sources, then store it in a field.

If information about the object can be derived from other sources but it's inefficient or inconvenient to keep deriving it, then document its relationship to other data, maybe mark it transient and store it in a field.

If you find a class with many fields then maybe it's time to break it up into smaller classes. Likewise, if a method with many local variables, then maybe it's time to try to break it up into smaller methods.

Community
  • 1
  • 1
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • Refering to the example, right now, I think I'll only need the array, so it makes sense to leave that array as the only field in the class. But obviously, I can't foresee if I'll need something else from that class in the future (maybe I'll need something and then I'll have to turn some of the local variables to fields. – Best Bloody Day Mar 30 '14 at 02:57
0

Assuming that you mean instance variables as per your example, rather than class / static variables. (If you did really mean static variables, then you have a whole lot of other problems to deal with ...)


Lets start with the "optimization" aspect of this Question.

The first thing to say is that the difference between the two approaches is probably insignificant. The chances are that it won't make a noticeable difference to the performance of the program. In your case, I would imagine you have at most few tens of instances of that class at any one time, so the difference in memory usage will be a few thousand bytes at most.

Having said that, there is a difference. When you declare the fields as instance fields, they will exist (and occupy heap memory) for the lifetime of the object. By contrast, local variables cease to exist when the enclosing method call ends. So using a local variable is likely to use less memory in the long term.


But the important issues here are readability, maintainability and correctness.

If you turn local "temporary" variables into instance variables, then there is scope for different methods ... or different calls to the same method ... interfering with each other via there use of the instance variables. Note that in some use-cases, the interference is unavoidable. For example, when two different threads call the same method on the same object simultaneously, or when a method directly or indirectly calls itself; i.e. recursion.

And the fact that such things could happen makes the code harder to read and harder to maintain. (Unless you are really familiar with the code, and are tracking all changes that anyone makes to it ... you can't be sure that something has broken your assumptions ... and you have to check.)

By contrast, you don't have these problems with local variables. They are guaranteed to not be visible to any other method call, on the current thread or another one.

In short, declaring variables as instance variables "just in order to keep things clear" is actually going to have the opposite effect. It is going to make things significantly less clear.


Finally, there was an interesting Question related to this on the Programmers site:

My conclusion in my Answer was this doesn't really qualify as an "anti-pattern" because it is not a design pattern. But nonetheless it is really bad.

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • So, what you mean to say is that, probably, coding the class this way is safer and faster at runtime BUT it will be very hard to understand (like if I spend some weeks without having a look at the code and then, when I try to change something or expand the program, I won't be able to understand my own code). Maybe adding javadoc or comments would help with future changes in the code? – Best Bloody Day Mar 30 '14 at 02:51
  • No. I'm not saying it will be safer and faster at runtime. It definitely won't be safer, and *I doubt* that it will be measurable faster. – Stephen C Mar 30 '14 at 03:44
  • Sorry, but just to clarify, are we talking about your example about the antipattern or about my example (I just get lost there)? And please, can you explain a little bit more about the inconvenience of my example? I'm asking because in my example I'm not calling a method from another method, just a method from the constructor. And in the end, the point of the example is to populate the pixel array. I don't see (remember, I'm a novice) any danger as it is right now. – Best Bloody Day Mar 30 '14 at 13:07
  • 1) I am talking about your example where you made the local variables into instance variables. 2) The issues are "readability, maintainability and correctness" ... not "convenience". 3) In an example as simple as yours, the code is easy enough to understand anyway. But for more complicated code that will not be the case. I probably can't explain it until you have had to read and understand a large and complicated program yourself. – Stephen C Mar 30 '14 at 15:13