001package beginner;
002
003import com.sandwich.koan.Koan;
004
005import java.io.IOException;
006
007import static com.sandwich.koan.constant.KoanConstants.__;
008import static com.sandwich.util.Assert.assertEquals;
009
010public class AboutExceptions {
011
012    private void doStuff() throws IOException {
013        throw new IOException();
014    }
015
016    @Koan
017    public void catchCheckedExceptions() {
018        String s;
019        try {
020            doStuff();
021            s = "code ran normally";
022        } catch (IOException e) {
023            s = "exception thrown";
024        }
025        assertEquals(s, __);
026    }
027
028    @Koan
029    public void useFinally() {
030        String s = "";
031        try {
032            doStuff();
033            s += "code ran normally";
034        } catch (IOException e) {
035            s += "exception thrown";
036        } finally {
037            s += " and finally ran as well";
038        }
039        assertEquals(s, __);
040    }
041
042    @Koan
043    public void finallyWithoutCatch() {
044        String s = "";
045        try {
046            s = "code ran normally";
047        } finally {
048            s += " and finally ran as well";
049        }
050        assertEquals(s, __);
051    }
052
053    private void tryCatchFinallyWithVoidReturn(StringBuilder whatHappened) {
054        try {
055            whatHappened.append("did something dangerous");
056            doStuff();
057        } catch (IOException e) {
058            whatHappened.append("; the catch block executed");
059            return;
060        } finally {
061            whatHappened.append(", but so did the finally!");
062        }
063    }
064
065    @Koan
066    public void finallyIsAlwaysRan() {
067        StringBuilder whatHappened = new StringBuilder();
068        tryCatchFinallyWithVoidReturn(whatHappened);
069        assertEquals(whatHappened.toString(), __);
070    }
071
072    @SuppressWarnings("finally")
073    // this is suppressed because returning in finally block is obviously a compiler warning
074    private String returnStatementsEverywhere(StringBuilder whatHappened) {
075        try {
076            whatHappened.append("try");
077            doStuff();
078            return "from try";
079        } catch (IOException e) {
080            whatHappened.append(", catch");
081            return "from catch";
082        } finally {
083            whatHappened.append(", finally");
084            // Think about how bad an idea it is to put a return statement in the finally block
085            // DO NOT DO THIS!
086            return "from finally";
087        }
088    }
089
090    @Koan
091    public void returnInFinallyBlock() {
092        StringBuilder whatHappened = new StringBuilder();
093        // Which value will be returned here?
094        assertEquals(returnStatementsEverywhere(whatHappened), __);
095        assertEquals(whatHappened.toString(), __);
096    }
097
098    private void doUncheckedStuff() {
099        throw new RuntimeException();
100    }
101
102    @Koan
103    public void catchUncheckedExceptions() {
104        // What do you need to do to catch the unchecked exception?
105        doUncheckedStuff();
106    }
107
108    @SuppressWarnings("serial")
109    static class ParentException extends Exception {
110    }
111
112    @SuppressWarnings("serial")
113    static class ChildException extends ParentException {
114    }
115
116    private void throwIt() throws ParentException {
117        throw new ChildException();
118    }
119
120    @Koan
121    public void catchOrder() {
122        String s = "";
123        try {
124            throwIt();
125        } catch (ChildException e) {
126            s = "ChildException";
127        } catch (ParentException e) {
128            s = "ParentException";
129        }
130        assertEquals(s, __);
131    }
132
133    @Koan
134    public void failArgumentValidationWithAnIllegalArgumentException() {
135        // This koan demonstrates the use of exceptions in argument validation
136        String s = "";
137        try {
138            s += validateUsingIllegalArgumentException(null);
139        } catch (IllegalArgumentException ex) {
140            s = "caught an IllegalArgumentException";
141        }
142        assertEquals(s, __);
143    }
144
145    @Koan
146    public void passArgumentValidationWithAnIllegalArgumentException() {
147        // This koan demonstrates the use of exceptions in argument validation
148        String s = "";
149        try {
150            s += validateUsingIllegalArgumentException("valid");
151        } catch (IllegalArgumentException ex) {
152            s = "caught an IllegalArgumentException";
153        }
154        assertEquals(s, __);
155    }
156
157    private int validateUsingIllegalArgumentException(String str) {
158        // This is effective and both the evaluation and the error message
159        // can be tailored which can be particularly handy if you're guarding
160        // against more than null values
161        if (null == str) {
162            throw new IllegalArgumentException("str should not be null");
163        }
164        return str.length();
165    }
166}