On Mon, 20 Sep 2021 11:27:32 GMT, Alexander Scherbatiy <[email protected]>
wrote:
>> The SunFontManager constructor and its subclasses seem too big, and
>> potentially throw some exceptions and this will ruin the holder idiom since
>> all subsequent calls to this method will fail.
>
> I wrote a simple example which uses DLC and lazy initialization holder class
> idioms. The FontManager is only created when it is accessed the first time
> via the getInstance() method in both cases and they both fail if an exception
> is thrown during the class initialization.
>
> Is the problem with Holder idiom that it throws `ExceptionInInitializerError`
> which contains the original exception as the cause whereas with DLC the
> original exception is directly thrown?
>
> public class FontManagerFactory {
>
> private static volatile FontManager instance;
>
> public static FontManager getInstanceDLC() {
>
> FontManager result = instance;
> if (result == null) {
> synchronized (FontManagerFactory.class) {
> result = instance;
> if (result == null) {
> instance = result = new FontManager("One", "Two",
> "Three");
> }
> }
> }
> return result;
> }
>
> public static FontManager getInstanceHolder() {
> return FontManagerHolder.instance;
> }
>
>
> public static void main(String[] args) {
> String lazyInitializationIdiom = args[0];
> System.out.printf("Use lazy initialization idiom: %s%n",
> lazyInitializationIdiom);
> if ("DLC".equals(args[0])) {
> System.out.printf("DLC FontManager instance: %s%n",
> getInstanceDLC());
> } else if ("Holder".equals(args[0])) {
> System.out.printf("Lazy Initialization Holder FontManager
> instance: %s%n", getInstanceHolder());
> }
> }
>
> private static class FontManagerHolder {
> private static final FontManager instance = new FontManager("One",
> "Two", "Three");
> }
> }
>
> class FontManager {
> public FontManager(String... args) {
> System.out.println(args[5]);
> }
> }
> ```
> DLC:
>
> java FontManagerFactory DLC
> Use lazy initialization idiom: DLC
> Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5
> out of bounds for length 3
> at FontManager.<init>(FontManagerFactory.java:41)
> at FontManagerFactory.getInstanceDLC(FontManagerFactory.java:12)
> at FontManagerFactory.main(FontManagerFactory.java:28)
>
> Hodler:
>
> java FontManagerFactory Holder
> Use lazy initialization idiom: Holder
> Exception in thread "main" java.lang.ExceptionInInitializerError
> at FontManagerFactory.getInstanceHolder(FontManagerFactory.java:20)
> at FontManagerFactory.main(FontManagerFactory.java:30)
> Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds
> for length 3
> at FontManager.<init>(FontManagerFactory.java:41)
> at
> FontManagerFactory$FontManagerHolder.<clinit>(FontManagerFactory.java:35)
> ... 2 more
Does that stack trace difference really matter?
if so, you could wrap the `return FontManagerHolder.instance;` in a try/catch
that throws that caused by:
try {
return FontManagerHolder.instance;
} catch (java.lang.ExceptionInInitializerError e) {
final Throwable cause = e.getCause();
if (cause instanceof RuntimeException re) {
throw re;
}
//could wrap in IllegalStateException or just throw the error
}
If this getInstance method is called with any frequency, getting rid of the
volatile access each time is a nice bonus.
-------------
PR: https://git.openjdk.java.net/jdk/pull/5517