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

Reply via email to