samples/gc/test/org/apidesign/gc/CompilerSurprisesTest.java
author Jaroslav Tulach <jtulach@netbeans.org>
Fri, 17 Oct 2008 09:01:08 +0200
changeset 283 f6369ddf822c
parent 282 b762c8fb572e
child 284 73477ff04378
permissions -rw-r--r--
ljnelson noted at 'http://weblogs.java.net/blog/jst/archive/2008/10/the_better_comp.html' that it is enough to make the variable final and the problem goes away. True, final helps, however the same code without final works as well. This very likely means that the compiler puts the variable into the topmost block where it is guaranteed to be fully initialized. That is why we need a hint warn about declaration of non-fully initialized variables.
     1 package org.apidesign.gc;
     2 
     3 import java.lang.ref.Reference;
     4 import java.lang.ref.WeakReference;
     5 import org.junit.Test;
     6 import org.netbeans.junit.NbTestCase;
     7 import static org.junit.Assert.*;
     8 
     9 // BEGIN: compiler.surprises.intro
    10 public class CompilerSurprisesTest {
    11     Reference<String> cache;
    12 
    13     public String factory() {
    14         String value = new String("Can I disappear?");
    15         cache = new WeakReference<String>(value);
    16         return value;
    17     }
    18 
    19     @Test
    20     public void checkThatTheValueCanDisapper() {
    21         String retValue = factory();
    22         retValue = null;
    23         assertGC("Nobody holds the string value anymore." +
    24                 "It can be GCed.", cache);
    25     }
    26 // FINISH: compiler.surprises.intro
    27 
    28 // BEGIN: compiler.surprises.error
    29     @Test
    30     public void obviouslyWithoutClearingTheReferenceItCannotBeGCed() {
    31         String retValue = factory();
    32 // commented out:        retValue = null;
    33         assertNotGC("The reference is still on stack." +
    34                 "It cannot be GCed.", cache);
    35     }
    36 // END: compiler.surprises.error
    37 
    38 
    39 // BEGIN: compiler.surprises.surprise
    40     boolean yes = true;
    41     @Test
    42     public void canItBeGCedSurprisingly() {
    43         String retValue;
    44         if (yes) {
    45             retValue = factory();
    46         }
    47         assertGC("Can be GCed, as retValue is not on stack!!!!", cache);
    48     }
    49 // END: compiler.surprises.surprise
    50 
    51 
    52 // BEGIN: compiler.surprises.fix
    53     boolean ok = true;
    54     @Test
    55     public void canItBeGCedIfInitialized() {
    56         String retValue = null;
    57         if (ok) {
    58             retValue = factory();
    59         }
    60         assertNotGC("Cannot be GCed as retValue is not stack", cache);
    61     }
    62 // END: compiler.surprises.fix
    63 
    64 // BEGIN: compiler.surprises.fix.init
    65     @Test public void properInitializationFixesTheProblem() {
    66         String retValue;
    67         if (yes) {
    68             retValue = factory();
    69         } else {
    70             retValue = null;
    71         }
    72         assertNotGC("Cannot be GCed, now the retValue is on stack", cache);
    73     }
    74 // END: compiler.surprises.fix.init
    75 
    76 // BEGIN: compiler.surprises.fix.final
    77     @Test public void properUsingFinalFixesTheProblem() {
    78         final String retValue;
    79         if (yes) {
    80             retValue = factory();
    81         } else {
    82             retValue = null;
    83         }
    84         assertNotGC("Cannot be GCed, now the retValue is on stack", cache);
    85     }
    86 // END: compiler.surprises.fix.final
    87 
    88 
    89     private static void assertGC(String msg, Reference<?> ref) {
    90         NbTestCase.assertGC(msg, ref);
    91     }
    92 
    93     private static void assertNotGC(String msg, Reference<?> ref) {
    94         try {
    95             NbTestCase.assertGC("Cannot be GCed. " + msg, ref);
    96         } catch (Error ex) {
    97             // OK
    98             return;
    99         }
   100         fail(msg + ref.get());
   101     }
   102 }