I have a "default" image file that's meant to be used if the "proper" image file doesn't exist. I'm using Maven to create the jar
and have placed the file under resources/images
, along with the other images I already have.
The file is defined in a class that has a few defaults:
public class Defaults {
public static final File BLANK_IMAGE = new File(relative_path_to_image);
//Other defaults
}
This works within the IDE, but not if I try to create a jar
- if I do and run it from the Command Prompt, it spits out the message I wrote for when a specific file can't be found.
I've looked at several potential solutions, but they all rely on non-static methods, which can't be used here since the File
is static (also, it makes no sense to instantiate something when all its instances would be identical - that's just a waste of time and resources).
Am I just stuck converting the File
to a String
and processing it inside every Object
that needs it with getResourceAsStream()
?
The file is placed on a few JLabel
instances (ones that are meant to have images that haven't been created yet) by first converting it into a BufferedImage
. I mention this in case there are better ways of achieving the same result that bypass the problem I'm having.
new File
means a file. An entry in a jar file isn't one. If you mention File
anywhere in the code, the game is lost immediately.
(also, it makes no sense to instantiate something when all its instances would be identical - that's just a waste of time and resources).
This mindset is highly detrimental. It leads to writing bad code. Bad in all senses:
Am I just stuck converting the File to a String and processing it inside every Object that needs it with getResourceAsStream()?
I think you severely misunderstand what File
is, then. File is just a light wrapper; it has one field, of type String, which represents the path. This:
private static final File MY_IMG_FILE = new File("/foo/bar");
public JLabel codeThatIsInvokedALot() {
return new JLabel(new ImageIcon(MY_IMG_FILE));
}
Is exactly as inefficient as:
public JLabel codeThatIsInvokedALot() {
return new JLabel(new ImageIcon(MyClass.class.getResource("/foo/bar"));
}
In the sense that you pay 1 point for the allocation of some objects, and 100,000,000,000 points (that's not an exaggeration, that is a roughly accurate sense of scale) for opening the jar file (or file on disk) and reading the actual bytes representing the image from it. If you're very very lucky your OS does some disk caching and will turn that into a 1 vs. 1 million gap instead.
If you want 'efficiency', you want to load the entire image once. "Create the file object only once" is completely meaningless for performance reasons. A File
object does not cache the contents of that file - just its location, and talking about 'caching' of this doesn't bear talking about (you're caching... about 80 bits worth. The lookup costs 500x more than creating it whole cloth, again not an exagerration).
So how is it done? Not difficult at all:
public class MyImages {
private final ImageIcon BLANK_IMAGE;
static {
BLANK_IMAGE = resourceToImage("/images/blankImage.png");
}
public static ImageIcon getBlankImage() { return BLANK_IMAGE; }
private static ImageIcon resourceToImage(String rsc) {
return new ImageIcon(MyImages.class.getResource(rsc));
}
}
This will:
MyImages
, it'll load the MyImages
class. Presumably, this will occur not quite 'on boot' but very soon afterwards naturally.return new JLabel(MyImages.getBlankIcon())
will (unless this is the very first time any code in this JVM execution touches MyImages) execute very quickly and doesn't touch the disk whatsoever.ImageIcon
.SomeContextClass.class.getResource
. This is strictly superior to going via the classloader, or using getClass()
instead of SomeContextClass.class
: These commonly shown alternatives fail in exotic circumstances (bootloaders, agents, etc - these get a null
classloader), fail in less exotic circumstances (modular systems where you subclass breaks getClass()
style), and MyClass.class.getResource
is simple, succint, idiomatic, and has fewer failure modes than all alternatives.