On Mon, 20 Sep 2021 16:55:49 GMT, Brett Okken
<[email protected]> wrote:
>> 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.
The difference is that Holder will fail that way forever, while the DLC have a
chance to resurrect on next call.
-------------
PR: https://git.openjdk.java.net/jdk/pull/5517