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.
jtulach@281
     1
package org.apidesign.gc;
jtulach@281
     2
jtulach@281
     3
import java.lang.ref.Reference;
jtulach@281
     4
import java.lang.ref.WeakReference;
jtulach@281
     5
import org.junit.Test;
jtulach@281
     6
import org.netbeans.junit.NbTestCase;
jtulach@281
     7
import static org.junit.Assert.*;
jtulach@281
     8
jtulach@281
     9
// BEGIN: compiler.surprises.intro
jtulach@281
    10
public class CompilerSurprisesTest {
jtulach@281
    11
    Reference<String> cache;
jtulach@281
    12
jtulach@281
    13
    public String factory() {
jtulach@281
    14
        String value = new String("Can I disappear?");
jtulach@281
    15
        cache = new WeakReference<String>(value);
jtulach@281
    16
        return value;
jtulach@281
    17
    }
jtulach@281
    18
jtulach@281
    19
    @Test
jtulach@281
    20
    public void checkThatTheValueCanDisapper() {
jtulach@281
    21
        String retValue = factory();
jtulach@281
    22
        retValue = null;
jtulach@282
    23
        assertGC("Nobody holds the string value anymore." +
jtulach@282
    24
                "It can be GCed.", cache);
jtulach@281
    25
    }
jtulach@281
    26
// FINISH: compiler.surprises.intro
jtulach@281
    27
jtulach@281
    28
// BEGIN: compiler.surprises.error
jtulach@281
    29
    @Test
jtulach@281
    30
    public void obviouslyWithoutClearingTheReferenceItCannotBeGCed() {
jtulach@281
    31
        String retValue = factory();
jtulach@281
    32
// commented out:        retValue = null;
jtulach@282
    33
        assertNotGC("The reference is still on stack." +
jtulach@282
    34
                "It cannot be GCed.", cache);
jtulach@281
    35
    }
jtulach@281
    36
// END: compiler.surprises.error
jtulach@281
    37
jtulach@281
    38
jtulach@281
    39
// BEGIN: compiler.surprises.surprise
jtulach@281
    40
    boolean yes = true;
jtulach@281
    41
    @Test
jtulach@281
    42
    public void canItBeGCedSurprisingly() {
jtulach@281
    43
        String retValue;
jtulach@281
    44
        if (yes) {
jtulach@281
    45
            retValue = factory();
jtulach@281
    46
        }
jtulach@281
    47
        assertGC("Can be GCed, as retValue is not on stack!!!!", cache);
jtulach@281
    48
    }
jtulach@281
    49
// END: compiler.surprises.surprise
jtulach@281
    50
jtulach@281
    51
jtulach@281
    52
// BEGIN: compiler.surprises.fix
jtulach@281
    53
    boolean ok = true;
jtulach@281
    54
    @Test
jtulach@281
    55
    public void canItBeGCedIfInitialized() {
jtulach@281
    56
        String retValue = null;
jtulach@281
    57
        if (ok) {
jtulach@281
    58
            retValue = factory();
jtulach@281
    59
        }
jtulach@281
    60
        assertNotGC("Cannot be GCed as retValue is not stack", cache);
jtulach@281
    61
    }
jtulach@281
    62
// END: compiler.surprises.fix
jtulach@281
    63
jtulach@283
    64
// BEGIN: compiler.surprises.fix.init
jtulach@283
    65
    @Test public void properInitializationFixesTheProblem() {
jtulach@283
    66
        String retValue;
jtulach@283
    67
        if (yes) {
jtulach@283
    68
            retValue = factory();
jtulach@283
    69
        } else {
jtulach@283
    70
            retValue = null;
jtulach@283
    71
        }
jtulach@283
    72
        assertNotGC("Cannot be GCed, now the retValue is on stack", cache);
jtulach@283
    73
    }
jtulach@283
    74
// END: compiler.surprises.fix.init
jtulach@283
    75
jtulach@283
    76
// BEGIN: compiler.surprises.fix.final
jtulach@283
    77
    @Test public void properUsingFinalFixesTheProblem() {
jtulach@283
    78
        final String retValue;
jtulach@283
    79
        if (yes) {
jtulach@283
    80
            retValue = factory();
jtulach@283
    81
        } else {
jtulach@283
    82
            retValue = null;
jtulach@283
    83
        }
jtulach@283
    84
        assertNotGC("Cannot be GCed, now the retValue is on stack", cache);
jtulach@283
    85
    }
jtulach@283
    86
// END: compiler.surprises.fix.final
jtulach@283
    87
jtulach@283
    88
jtulach@281
    89
    private static void assertGC(String msg, Reference<?> ref) {
jtulach@281
    90
        NbTestCase.assertGC(msg, ref);
jtulach@281
    91
    }
jtulach@281
    92
jtulach@281
    93
    private static void assertNotGC(String msg, Reference<?> ref) {
jtulach@281
    94
        try {
jtulach@281
    95
            NbTestCase.assertGC("Cannot be GCed. " + msg, ref);
jtulach@281
    96
        } catch (Error ex) {
jtulach@281
    97
            // OK
jtulach@281
    98
            return;
jtulach@281
    99
        }
jtulach@281
   100
        fail(msg + ref.get());
jtulach@281
   101
    }
jtulach@281
   102
}