it strongly depends on the framework you are using. In general you are right, global variables are often treated as anti-pattern. But you have to understand the reason, which is mainly testability.
To get "global" things tested you usually use patterns like Factories, Provider often in combination with dependency injection (e.g. Spring, Guide).
In the end you are caching. For caching you can also use some framework like EHCache. But maybe that's to much overhead for you.
To keep it simple and in plain Java I would suggest something like this (just first draft, not tested):
public class FileCache {
Map<String, String> fileContents = new HashMap<String, String>();
public void loadFile(String path) {
if (fileContents.contains(path)) {
return fileContents.get(path);
}
// Loading logic
String content = loadContentOfFile(path);
fileContents.put(path, content);
return content;
}
}
With this you keep your caching a bit scalable (you can cache as many files as you want) and it will be easy to test this class. But in the end you end up with some global place where you need to access this class.
And then you either have Dependency Injection, a static variable or some Singleton.
With a singleton you should care to keep it simple, since it's again hard to test.
public class FileContentProvider {
private static FileContentProvider instance;
private final FileCache fileCache = new FileCache();
public static FileContentProvider getInstance() {
if (instance == null) {
instance = new FileContentProvider();
}
return instance;
}
public FileCache getFileCache() {
return fileCache;
}
}