I wrote an abstract class to contain all rules of the application because I need them almost everywhere in my application. So most of what it contains is static final
variables, something like this:
public abstract class appRules
{
public static final boolean IS_DEV = true;
public static final String CLOCK_SHORT_TIME_FORMAT = "something";
public static final String CLOCK_SHORT_DATE_FORMAT = "something else";
public static final String CLOCK_FULL_FORMAT = "other thing";
public static final int USERNAME_MIN = 5;
public static final int USERNAME_MAX = 16;
// etc.
}
The class is big and contains LOTS of such variables.
My Question:
- 开发者_开发百科Isn't setting static variables means these variables are floating in memory all the time?
- Do you suggest insteading of
having an abstract class, I have a
instantiable class with non-static
variables (just
public final
), so I instantiate the class and use the variables only when I need them. - Or is what am I doing is completely wrong approach and you suggest something else?
Given modern machines, RAM capacity etc, you'd have to have many thousand rules (if not millions) to make any noticable difference, both performance- and memory-wise.
So the question is not whether that's going to hog your system: it's not.
The question is whether that's a good practice.
I have of course used this pattern myself, so I understand it's usefulness. The main drawback however is: it makes your code untestable. Since there is no easy way to set these values differently for unit tests (as opposed to property files where you just put a different file on the classpath), it will be very hard to test functionality of individual modules without wiring up the whole application, but that depends on what you keep in those constants.
I guess maybe I'd try to split things up, have one constant class per module, package etc. and initialize those constants from property files:
private static final String CONSTANT_FOO;
private static final String CONSTANT_BAR;
static{
try{
Properties props = new Properties();
InputStream is =
MyConstantClass.class
.getResourceAsStream("my.module.properties");
props.load(is);
// you'll actually want to move this to finally, but I'm lazy
is.close();
CONSTANT_FOO = props.get("constants.foo");
CONSTANT_BAR = props.get("constants.bar");
}catch(Exception e){
throw new IllegalStateException(e);
}
}
That way your code gets more testable and configurable, while still enjoying the benefits of global configuration constants.
Isn't setting static variables means these variables are floating in memory all the time?
Yes. But unless, you have a really, really large number of constants like that, it isn't going to make much difference. Besides, if you really need them to be named constants, you cannot really improve on your current approach.
Do you suggest instead of having an abstract class, I have a instantiable class with non-static variables (just public final), so I instantiate the class and use the variables only when I need them.
No. That won't take any less memory. The JVM would have to keep the String objects corresponding to the literals anyway, so that it can assign them to the (non-static) variables when an instance of the class was created.
Add to this the possibility that you may create multiple instances of the classes, which uses more space and consumes more CPU cycles.
Or is what am I doing is completely wrong approach?
I don't think so.
@Peter Lawrey points out that there are theoretical limits on the number of static fields that a class can have. The limiting factors include:
- the size of the bytecode segment for the Cinit pseudo-method (2G bytes) - JVM spec 4.7.3
- the number of fields in a class (64K) - JVM spec 4.5
- the number of string literals in a class (64K) - JVM spec 4.4.3
However, this is unlikely to be a practical problem. I cannot imagine a program really needing so many constants that the limits come into play. Besides, you could just split the constants over multiple classes.
Break the list of variables into a bunch of variables based on the sub modules of your application. Place the set of variables in a separate classes. Instantiate the class and store its object in the session.
whenever you need to use any variable, refer the object from session. If you are not using any variable from an object, release the object from the session.
I hope it wont take much of your server's memory.
I think it's not that much overhead. Thinking practically, lets say, you 3000 rules
, each rule is a String of 1000 characters
. Your memory consumption is 3MB
. Is that too big?
I would say, its alright, even if you have 30,000 rules. Don't bother much about memory usage. This is not one of the area that's going to cause out-of-memory error.
I think it's OK for memory issue. If there are large objects to use, lazy-initialize can be a way to save memory. Or java.util.prefs.Preferences
can be a choice.
If I were you, I would use name RuleUtils
instead of appRules
, and make it final, as abstract class should be designed for extension.
Its worth putting the amount of memory you are using perspective. Are you using a mobile device or a PC or a server? For a Server you can by a machine with 24 GB for around £1,800. Thats about £75 per GB, or 8 cents per MB.
If your time costs the company £50 per hour, its not worth spending even 1 minute to save a 10 MB.
On minimum wage, its not worth spending 1 minute to save 1 MB in a PC or server.
精彩评论