Answers.Body: <p>In Java and many other languages that followed it, Exceptions are un-exceptional: e.g. it is not exceptional to get to the end of a file.</p>
  <p>Your example of removing an item from an empty list, is a contract pre-condition violation. Add a method <code>bool list.is_empty()</code>. Then a pre-condition <code>!is_empty()</code>. If the precondition is not met, then throw an error. Don't catch it, as it indicates a programming error: the program should have checked the pre-condition.</p>
  <p>More importantly, are exceptions in the syllabus?</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-26T20:50:35.180Z
Answers.LastActivityDate: 2023-11-26T20:50:35.180Z
Answers.UserDisplayName: ctrl-alt-delor
Answers.Body: <p>Create a type value or error (but nothing else: so not object)</p>
  <p>e.g.</p>
  <pre><code>class value_or_error {
      private int _value;
      private bool _is_error;
  
      public bool is_error(){
         return _is_error();
      }
      public int value() {
         if _is_error then throw;
         return _value;
      }
  }
  </code></pre>
  <p>Sorry if it does not compile (no javac installed)</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-26T21:04:27.767Z
Answers.LastActivityDate: 2023-11-26T21:04:27.767Z
Answers.UserDisplayName: ctrl-alt-delor
Answers.Body: <p>I'm not sure what the progression is in your education system, but the one I went through to learn programming as a complete novice in Java (~2015, in the USA, at a community college) went roughly like this:</p>
  <ul>
  <li>Semester 1: hello world, variables, primitive types, operations, conditions, loops, arrays, lists, simple methods like a temperature converter, basic language features like rounding numbers and algorithms like searching for an item in a list and bubble sort.</li>
  <li>Semester 2: classes, multi-file programs, simple GUI programs (Java swing), basic recursion with integers or arrays, error handling, 2d arrays and basic Java collections.</li>
  <li>Semester 3: data structures and algorithms, including time complexity, bags, linked lists, stacks, queues, trees, graphs and operations on these data structures like sorting, searching, adding, removing, inserting and internal operations necessary to maintain the integrity of the data structure.</li>
  </ul>
  <p>High school students I work with nowadays tend to go through something similar, except they start with Python in semester 1, or maybe with Scratch if they're younger, (not counting the countless possible detours into robotics, Lego Mindstorms, Minecraft modding, etc).</p>
  <p>In any case, by the time students learn stacks and queues, it's assumed that the basic language features like error handling have been covered to the extent that students have at least a fundamental level of proficiency/familiarity with them. If this is not the case, it shouldn't be too much of a stretch to cover a topic like error handling, at least in a way that makes it minimally usable within the context of your class.</p>
  <p>On a deeper level, if it does feel like a stretch to &quot;ramp up&quot; students on error handling, and they aren't arriving with any experience in it, maybe your curriculum is teaching data structures too early, without adequate fundamentals in place. A data structure course will be painful for any students that aren't comfortable with classes or collections, for example. Rudimentary error handling seems to fit into this prerequisite category.</p>
  <p>Method contracts are very important for data structures and algorithms, as <a href="https://cseducators.stackexchange.com/a/7932/9426">this answer</a> points out. Thinking about how a method should behave in exceptional cases is important. Promoting language conventions is important. The habits and skills students develop in reimplementing classic data structures teach key software engineering principles which students will likely use in their career more than the algorithm logic.</p>
  <p>Most textbooks for third-semester data structures and algorithms use errors. Returning false to indicate failure won't help you searching for an element in a <code>Boolean</code> collection. Returning null can occasionally be acceptable, but means that data structures can't store null values, and calling code needs to assert or handle the possibility of a failure, effectively approximating <code>try</code>/<code>catch</code> but without the explicitness and safety net. Returning -1 is standard for &quot;index of&quot; searches, because it's not a possible return value.</p>
  <p>Sure, some language like JavaScript tend to avoid throwing errors (popping an empty array returns undefined, for example: <code>[].pop()</code>), but I don't think this is necessarily a good way to teach data structures and algorithms in Java. The contracts are less clear and subtle bugs can easily occur. In a course that does use JS or Python to teach data structures, I'd be more inclined to follow the conventions of the language. Along that line of thought, if in doubt when teaching a Java data structures course, it seems reasonable to follow the contracts given by <code>java.util.Collections</code>. The merit of using Java for teaching is the explicitness of the language, types, generics, clear method contracts, named exceptions, class organization, and so forth. Taking pains to avoid any of these concepts feels like a missed opportunity to use the language as it was designed.</p>
  <p>Given your circumstances, if you feel <code>try</code>/<code>catch</code> is too much for your students to handle, you can still teach students about errors in general and let them throw uncaught errors. You can provide test harnesses or boilerplate that uses <code>try</code>/<code>catch</code> or JUnit assertions as examples. In some ways, throwing and letting the program fail is less work than handling exceptional cases at every branch after every method call that may fail.</p>
  <p>You can simplify exceptions in the following ways, summarizing and extending ideas from above:</p>
  <ul>
  <li>In general, permit programs to crash, preferably with a clear message. This is the lesser evil than continuing on with unhandled illegal state. If there's a contract violation, students should report it as soon as possible rather than allow the program to potentially silently mess up critical data or crash in a spot far removed from the violation. <code>catch</code> is a necessary but dangerous tool that can be misused to suppress problems.</li>
  <li>Use only <code>throw</code> and <code>throws</code> and de-emphasize or skip <code>try</code>/<code>catch</code>.</li>
  <li>Offer test harnesses and boilerplate that handles errors with <code>try</code>/<code>catch</code> or JUnit assertions. From the start, novice Java students won't understand what <code>public static void main(String[] args)</code> means, so they're used to a certain amount of accepting things on faith temporarily.</li>
  <li>Don't worry too much about error classes and inheritance. Explicit consideration for the exceptional state is the main part, so just using <code>IllegalStateException</code> or even <code>Exception</code> can be permissible for the purposes of simplicity.</li>
  <li>If you do catch errors, maybe allow <a href="https://softwareengineering.stackexchange.com/questions/319088/is-indiscriminately-catching-exceptions-pokemon-exception-handling-ever-accept">Pokemon exception handling</a> for starters, with a cautionary note.</li>
  <li>If <code>throw</code> is too much, stick to <code>assert</code>. This ensures the students are thinking carefully about pre/post conditions and contracts, without any syntactical complexity or work to be done in the caller. The gotchas here, though, are that assertions are disabled by default, and that <code>assert</code> statements <a href="https://stackoverflow.com/a/47131532/6243352">should be side-effect free</a>.</li>
  </ul>
  <p>Here are some code snippets to help make the above suggestions more concrete.</p>
  <p>Stage 1: just add <code>assert</code> (and compile with <code>-ea</code>):</p>
  <pre class="lang-java prettyprint-override"><code>import java.util.ArrayList;
  
  class Stack&lt;T&gt; {
      private ArrayList&lt;T&gt; stack;
      
      public Stack() {
          stack = new ArrayList&lt;&gt;();
      }
  
      public void push(T element) {
          stack.add(element);
      }
  
      public T pop() {
          assert !stack.isEmpty() : &quot;Tried to pop an empty stack&quot;;
          return stack.remove(stack.size() - 1);
      }
  }
  
  public class Main {
      public static void main(String[] args) {
          var stack = new Stack&lt;Integer&gt;();
          stack.push(1);
          stack.push(2);
          System.out.println(stack.pop());
          System.out.println(stack.pop());
          System.out.println(stack.pop()); // crashes
      }
  }
  </code></pre>
  <p>You could go a step further and add pre/post condition assertions to help solidify the contract.</p>
  <p>If the asserts stopping the test harness is a problem, you can have students comment out and label these lines by the error they trigger, disable the <code>-ea</code> flag or use separate harness programs for each assertion failure &quot;test&quot;.</p>
  <p>Stage 2: add <code>throw</code>:</p>
  <pre class="lang-java prettyprint-override"><code>import java.lang.IllegalStateException;
  import java.util.ArrayList;
  
  class Stack&lt;T&gt; {
      private ArrayList&lt;T&gt; stack;
      
      public Stack() {
          stack = new ArrayList&lt;&gt;();
      }
  
      public void push(T element) {
          stack.add(element);
      }
  
      public T pop() {
          if (stack.isEmpty()) {
              throw new IllegalStateException(&quot;Tried to pop an empty stack&quot;);
          }
  
          return stack.remove(stack.size() - 1);
      }
  }
  </code></pre>
  <p>Optionally, provide a simple test harness for the student with <code>try</code>/<code>catch</code>:</p>
  <pre class="lang-java prettyprint-override"><code>public class Main {
      public static void main(String[] args) {
          var stack = new Stack&lt;Integer&gt;();
          stack.push(1);
          stack.push(2);
          System.out.println(stack.pop());
          System.out.println(stack.pop());
  
          try {
              System.out.println(stack.pop());
          }
          catch (IllegalStateException ex) {
              System.err.println(ex); 
          }
      }
  }
  </code></pre>
  <p>Hopefully one of these seems doable.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-21T22:00:10.007Z
Answers.Text: Wow! That's a really detailed answer and thank you especially for providing the code snippets.  I'm keen that my students don't learn anything wrong (or bad habits) while wanting not to overload them.  I think they can cope with error handling -- certainly as a concept -- it's just me wanting to space out the concepts a little to allow them to get used to the syntax.  So in a few weeks I'd hope they'll be `try/catch`ing with the best of them, but for the moment I'm trying to chart the smoothest path to that point. Again, many thanks for the detailed answer!
Answers.UserDisplayName: Andrew Stacey
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-29T21:01:49.203Z
Answers.Text: There's a lot here that I'll keep coming back to as I learn more myself.  A crucial point for me (this time) was to de-emphasise the `try/catch` part of exception handling (your second bullet point).
Answers.UserDisplayName: Andrew Stacey
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-21T20:48:23.867Z
Answers.LastActivityDate: 2023-11-21T21:15:43.053Z
Answers.LastEditDate: 2023-11-21T21:15:43.053Z
Answers.UserDisplayName: ggorlen
Answers.Body: <p>This answer is based on a software engineering point of view, in not teaching things that contradict best practices. (And there are lots of misconceptions and bad practices around exception handling, both in &quot;professional&quot; code as well as in lots of web resources, showing that many developers were trained the wrong way.)</p>
  <p>To me the most important concept is that a method has a contract, something it is supposed to do (documented in a Javadoc comment), and that sometimes it cannot fulfill that contract, which it MUST communicate to its caller, and (by modern best practice) SHOULD do by throwing an exception.</p>
  <p>As soon as methods arise that can really fail (and that's how I understand your question), please throw exceptions. Special return values like <code>-1</code> or <code>null</code> have been the standard in the 1970s, and there is good reason why nowadays they have been replaced by exceptions.</p>
  <p>Of course, going into details of exception handling will take quite some time in your course. But you can use a shortcut with something like:</p>
  <blockquote>
  <p>Here's a method that can fail. When we detect the failure situation,
  we <code>throw new Exception(&quot;description text&quot;);</code>. That's a special way of exitting,
  telling the caller that we failed. It has to be declared
  in the method header with a <code>throws Exception</code> clause. Further on,
  we'll learn that there are lots of different exception types, and
  various ways what to do in case of an exception, instead of aborting
  the whole program. But for the moment, that's enough for us to know.</p>
  </blockquote>
  <p>Don't catch exceptions. Catching an exception means that a caller can fulfill its job even though the callee failed, which is rarely true. So this should only be covered under a &quot;Recovering from problems&quot; topic.</p>
  <p>If you don't want to follow this path, and instead want to return a special value, make sure that every caller checks whether it got the special return value, and then returns with its special return value and so on. Experience told us that this was very often forgotten, making the following steps produce nonsense, and leading to bugs that were hard to analyze and fix. This finally led to the wide-spread adoption of the &quot;exceptions&quot; pattern.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-20T21:49:31.733Z
Answers.Text: Your opening sentence is something I'm keen to adhere to - while it would be horrendous to teach _everything_ at once, I don't want to simplify to the extent that what I'm saying is wrong or bad practice. But I have a practical problem with your advice to not catch exceptions in that the IDE (IntelliJ) doesn't like that.  I shall need to experiment a bit more to see how strongly it objects, but in the meantime is there an easy way to say to Java "Just fail on all exceptions"?
Answers.UserDisplayName: Andrew Stacey
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-21T04:44:56.603Z
Answers.Text: I agree: you don't necessarily need to use `try`/`catch` in the caller. This makes it both good and fairly easy, if you type methods `throws Exception` and teach students to `throw Exception("description of contract violation")`. The other way to simplify is to not worry too much about the type of exceptions. Your testing harness boilerplate can use `try`/`catch` or proper JUnit assertions, as applicable (students need not understand it fully right off the bat). That said, for many data structures it's acceptable to return `null` when lookup operations fail as many Java util collections do.
Answers.UserDisplayName: ggorlen
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-23T15:44:57.463Z
Answers.Text: @ggorlen Yes, and IMHO it all depends on the contract that you have in mind, whether you expect some element not to exist, and include that in the contract. Or you insist that an object is found, and then not finding one is a failure. It's like the distinction between the words "search" and "find".
Answers.UserDisplayName: Ralf Kleberhoff
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-29T21:00:09.970Z
Answers.Text: I _almost_ accepted this one because your phrase "Don't catch exceptions" prompted an important shift in my thinking, and today my students showed how to get our IDE to stop complaining that I wasn't `try/catch`ing the exceptions (by adding `throws Exception` to the `main` declaration).  So thank you for that phrase!
Answers.UserDisplayName: Andrew Stacey
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-20T09:54:37.067Z
Answers.LastActivityDate: 2023-11-20T09:54:37.067Z
Answers.UserDisplayName: Ralf Kleberhoff
Answers.Body: <p>You may need to teach this concept, but I'd do it at the point it becomes be best option. If things can fail, some sort of test or similar action is needed.</p>
  <p>For a list of objects, one can return null in many cases (unless null is a valid value). If a list contains non-negatives you can return -1, say, and test for it. This implies you have already taught other structured statements, such as if-else, etc. So, such statements are no longer a mystery to them.</p>
  <p>After you have done this a few times you can discuss the more subtle cases.</p>
  <p>First, show them a program that fails (crashes) due to this sort of situation. Then show how a program can recover from such a situation with a try-catch. It shouldn't need to be a big step.</p>
  <p>First examples might do no more than give better error messages before halting. Once the structure and execution are clear you can do more with actual recovery.</p>
  <p>And, Python can <em>raise</em> and catch exceptions also, in which case you might draw on their knowledge of that language.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-19T22:58:26.443Z
Answers.Text: Thank you.  Returning `null` sounds like a reasonable placeholder (which is what I'm after).  You're right to assume that they know about the various structured statements, and while some might have met python's exception handling then I don't want to assume it and also don't want to introduce too many things in one go.  At this stage, we're not writing complicated programs, so just testing for `null` is fine.
Answers.UserDisplayName: Andrew Stacey
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-26T20:52:10.553Z
Answers.Text: null and un-exceptional exceptions, are two of the biggest mistakes in programming. Does Java have types that can be value or error (but nothing else)? I think it may be possible to make a type with `class`.
Answers.UserDisplayName: ctrl-alt-delor
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-19T20:17:07.460Z
Answers.LastActivityDate: 2023-11-19T20:17:07.460Z
Answers.UserDisplayName: Buffy
Body: <p><strong>TL;DR</strong> How important is the <code>try ... catch</code> syntax when starting out with learning Java?</p>
  <p><em>Background</em>: I'm teaching A level CS in the UK (age 16-18) and we're using Java as our primary language.  The students are already familiar with python.</p>
  <p>To teach common data types (such as queues and stacks), we code them.  Due to specification considerations, the underlying structure is an array (fixed length, single type).  There are a couple of places where we need to code a message that might not always work, such as removing an element from an empty queue or putting an element on a full stack.  In python, I'd just return <code>False</code> from the method - it's not perfect but pedagogically it allows me to focus on other things.  In Java, I have to return something of the right signature, so if something goes wrong then I need to throw an exception.  But then in the main program I need to have a <code>try ... catch</code> structure.</p>
  <p>The goal is to use the program to understand the data type, while getting a bit more experience with Java.  So I don't want to throw too much at the students all in one go, and <code>try ... catch</code> is not something they are used to.  I understand its importance as a programming paradigm but am just trying to sequence the introduction of concepts and figure out where this one should be introduced.</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-11-19T17:27:36.787Z
Comments.Text: Wasn't sure on the tags, please edit to add appropriate ones
Comments.UserDisplayName: Andrew Stacey
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-11-19T20:09:14.333Z
Comments.Text: In Java you can return null in place of any object. But you still have to test for it. lists of ints are harder unless a non-negative is expected.
Comments.UserDisplayName: Buffy
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-11-21T05:59:31.760Z
Comments.Text: What happens if you use `throw` without `try`? [I prefer the Python word `raise` -- less imperative] Sure you can't error **recover**. But then the idea of errors should be more fundamental than handling no?
Comments.UserDisplayName: Rushi
Tags: <java><programming-paradigms>
Title: When teaching Java, should I teach try-catch from the outset?
ThreadText: # When teaching Java, should I teach try-catch from the outset?
  
  (Asked by: username_0 on 2023-11-19)
  
  **TL;DR** How important is the `try ... catch` syntax when starting out with learning Java?
  
  *Background*: I'm teaching A level CS in the UK (age 16-18) and we're using Java as our primary language. The students are already familiar with python.
  
  To teach common data types (such as queues and stacks), we code them. Due to specification considerations, the underlying structure is an array (fixed length, single type). There are a couple of places where we need to code a message that might not always work, such as removing an element from an empty queue or putting an element on a full stack. In python, I'd just return `False` from the method - it's not perfect but pedagogically it allows me to focus on other things. In Java, I have to return something of the right signature, so if something goes wrong then I need to throw an exception. But then in the main program I need to have a `try ... catch` structure.
  
  The goal is to use the program to understand the data type, while getting a bit more experience with Java. So I don't want to throw too much at the students all in one go, and `try ... catch` is not something they are used to. I understand its importance as a programming paradigm but am just trying to sequence the introduction of concepts and figure out where this one should be introduced.
  
  **Tags:** java, programming-paradigms
  
  > **Comments:**
  > **username_0**: Wasn't sure on the tags, please edit to add appropriate ones  
  > **username_1**: In Java you can return null in place of any object. But you still have to test for it. lists of ints are harder unless a non-negative is expected.  
  > **username_2**: What happens if you use `throw` without `try`? [I prefer the Python word `raise` -- less imperative] Sure you can't error **recover**. But then the idea of errors should be more fundamental than handling no?  
  
  ---
  
  ## 5 answers
  
  ### Answer by username_4 on 2023-11-21. Score: 2 | Accepted answer
  
  I'm not sure what the progression is in your education system, but the one I went through to learn programming as a complete novice in Java (~2015, in the USA, at a community college) went roughly like this:
  
  * Semester 1: hello world, variables, primitive types, operations, conditions, loops, arrays, lists, simple methods like a temperature converter, basic language features like rounding numbers and algorithms like searching for an item in a list and bubble sort.
  * Semester 2: classes, multi-file programs, simple GUI programs (Java swing), basic recursion with integers or arrays, error handling, 2d arrays and basic Java collections.
  * Semester 3: data structures and algorithms, including time complexity, bags, linked lists, stacks, queues, trees, graphs and operations on these data structures like sorting, searching, adding, removing, inserting and internal operations necessary to maintain the integrity of the data structure.
  
  High school students I work with nowadays tend to go through something similar, except they start with Python in semester 1, or maybe with Scratch if they're younger, (not counting the countless possible detours into robotics, Lego Mindstorms, Minecraft modding, etc).
  
  In any case, by the time students learn stacks and queues, it's assumed that the basic language features like error handling have been covered to the extent that students have at least a fundamental level of proficiency/familiarity with them. If this is not the case, it shouldn't be too much of a stretch to cover a topic like error handling, at least in a way that makes it minimally usable within the context of your class.
  
  On a deeper level, if it does feel like a stretch to "ramp up" students on error handling, and they aren't arriving with any experience in it, maybe your curriculum is teaching data structures too early, without adequate fundamentals in place. A data structure course will be painful for any students that aren't comfortable with classes or collections, for example. Rudimentary error handling seems to fit into this prerequisite category.
  
  Method contracts are very important for data structures and algorithms, as [this answer](https://cseducators.stackexchange.com/a/7932/9426) points out. Thinking about how a method should behave in exceptional cases is important. Promoting language conventions is important. The habits and skills students develop in reimplementing classic data structures teach key software engineering principles which students will likely use in their career more than the algorithm logic.
  
  Most textbooks for third-semester data structures and algorithms use errors. Returning false to indicate failure won't help you searching for an element in a `Boolean` collection. Returning null can occasionally be acceptable, but means that data structures can't store null values, and calling code needs to assert or handle the possibility of a failure, effectively approximating `try`/`catch` but without the explicitness and safety net. Returning -1 is standard for "index of" searches, because it's not a possible return value.
  
  Sure, some language like JavaScript tend to avoid throwing errors (popping an empty array returns undefined, for example: `[].pop()`), but I don't think this is necessarily a good way to teach data structures and algorithms in Java. The contracts are less clear and subtle bugs can easily occur. In a course that does use JS or Python to teach data structures, I'd be more inclined to follow the conventions of the language. Along that line of thought, if in doubt when teaching a Java data structures course, it seems reasonable to follow the contracts given by `java.util.Collections`. The merit of using Java for teaching is the explicitness of the language, types, generics, clear method contracts, named exceptions, class organization, and so forth. Taking pains to avoid any of these concepts feels like a missed opportunity to use the language as it was designed.
  
  Given your circumstances, if you feel `try`/`catch` is too much for your students to handle, you can still teach students about errors in general and let them throw uncaught errors. You can provide test harnesses or boilerplate that uses `try`/`catch` or JUnit assertions as examples. In some ways, throwing and letting the program fail is less work than handling exceptional cases at every branch after every method call that may fail.
  
  You can simplify exceptions in the following ways, summarizing and extending ideas from above:
  
  * In general, permit programs to crash, preferably with a clear message. This is the lesser evil than continuing on with unhandled illegal state. If there's a contract violation, students should report it as soon as possible rather than allow the program to potentially silently mess up critical data or crash in a spot far removed from the violation. `catch` is a necessary but dangerous tool that can be misused to suppress problems.
  * Use only `throw` and `throws` and de-emphasize or skip `try`/`catch`.
  * Offer test harnesses and boilerplate that handles errors with `try`/`catch` or JUnit assertions. From the start, novice Java students won't understand what `public static void main(String[] args)` means, so they're used to a certain amount of accepting things on faith temporarily.
  * Don't worry too much about error classes and inheritance. Explicit consideration for the exceptional state is the main part, so just using `IllegalStateException` or even `Exception` can be permissible for the purposes of simplicity.
  * If you do catch errors, maybe allow [Pokemon exception handling](https://softwareengineering.stackexchange.com/questions/319088/is-indiscriminately-catching-exceptions-pokemon-exception-handling-ever-accept) for starters, with a cautionary note.
  * If `throw` is too much, stick to `assert`. This ensures the students are thinking carefully about pre/post conditions and contracts, without any syntactical complexity or work to be done in the caller. The gotchas here, though, are that assertions are disabled by default, and that `assert` statements [should be side-effect free](https://stackoverflow.com/a/47131532/6243352).
  
  Here are some code snippets to help make the above suggestions more concrete.
  
  Stage 1: just add `assert` (and compile with `-ea`):
  
  ```java
  import java.util.ArrayList;
  
  class Stack<T> {
      private ArrayList<T> stack;
      
      public Stack() {
          stack = new ArrayList<>();
      }
  
      public void push(T element) {
          stack.add(element);
      }
  
      public T pop() {
          assert !stack.isEmpty() : "Tried to pop an empty stack";
          return stack.remove(stack.size() - 1);
      }
  }
  
  public class Main {
      public static void main(String[] args) {
          var stack = new Stack<Integer>();
          stack.push(1);
          stack.push(2);
          System.out.println(stack.pop());
          System.out.println(stack.pop());
          System.out.println(stack.pop()); // crashes
      }
  }
  
  ```
  
  You could go a step further and add pre/post condition assertions to help solidify the contract.
  
  If the asserts stopping the test harness is a problem, you can have students comment out and label these lines by the error they trigger, disable the `-ea` flag or use separate harness programs for each assertion failure "test".
  
  Stage 2: add `throw`:
  
  ```java
  import java.lang.IllegalStateException;
  import java.util.ArrayList;
  
  class Stack<T> {
      private ArrayList<T> stack;
      
      public Stack() {
          stack = new ArrayList<>();
      }
  
      public void push(T element) {
          stack.add(element);
      }
  
      public T pop() {
          if (stack.isEmpty()) {
              throw new IllegalStateException("Tried to pop an empty stack");
          }
  
          return stack.remove(stack.size() - 1);
      }
  }
  
  ```
  
  Optionally, provide a simple test harness for the student with `try`/`catch`:
  
  ```java
  public class Main {
      public static void main(String[] args) {
          var stack = new Stack<Integer>();
          stack.push(1);
          stack.push(2);
          System.out.println(stack.pop());
          System.out.println(stack.pop());
  
          try {
              System.out.println(stack.pop());
          }
          catch (IllegalStateException ex) {
              System.err.println(ex); 
          }
      }
  }
  
  ```
  
  Hopefully one of these seems doable.
  
  > **Comments:**
  > **username_0**: Wow! That's a really detailed answer and thank you especially for providing the code snippets.  I'm keen that my students don't learn anything wrong (or bad habits) while wanting not to overload them.  I think they can cope with error handling -- certainly as a concept -- it's just me wanting to space out the concepts a little to allow them to get used to the syntax.  So in a few weeks I'd hope they'll be `try/catch`ing with the best of them, but for the moment I'm trying to chart the smoothest path to that point. Again, many thanks for the detailed answer!  
  > **username_0**: There's a lot here that I'll keep coming back to as I learn more myself.  A crucial point for me (this time) was to de-emphasise the `try/catch` part of exception handling (your second bullet point).  
  
  ---
  
  ### Answer by username_5 on 2023-11-20. Score: 2
  
  This answer is based on a software engineering point of view, in not teaching things that contradict best practices. (And there are lots of misconceptions and bad practices around exception handling, both in "professional" code as well as in lots of web resources, showing that many developers were trained the wrong way.)
  
  To me the most important concept is that a method has a contract, something it is supposed to do (documented in a Javadoc comment), and that sometimes it cannot fulfill that contract, which it MUST communicate to its caller, and (by modern best practice) SHOULD do by throwing an exception.
  
  As soon as methods arise that can really fail (and that's how I understand your question), please throw exceptions. Special return values like `-1` or `null` have been the standard in the 1970s, and there is good reason why nowadays they have been replaced by exceptions.
  
  Of course, going into details of exception handling will take quite some time in your course. But you can use a shortcut with something like:
  
  > Here's a method that can fail. When we detect the failure situation,
  > we `throw new Exception("description text");`. That's a special way of exitting,
  > telling the caller that we failed. It has to be declared
  > in the method header with a `throws Exception` clause. Further on,
  > we'll learn that there are lots of different exception types, and
  > various ways what to do in case of an exception, instead of aborting
  > the whole program. But for the moment, that's enough for us to know.
  
  Don't catch exceptions. Catching an exception means that a caller can fulfill its job even though the callee failed, which is rarely true. So this should only be covered under a "Recovering from problems" topic.
  
  If you don't want to follow this path, and instead want to return a special value, make sure that every caller checks whether it got the special return value, and then returns with its special return value and so on. Experience told us that this was very often forgotten, making the following steps produce nonsense, and leading to bugs that were hard to analyze and fix. This finally led to the wide-spread adoption of the "exceptions" pattern.
  
  > **Comments:**
  > **username_0**: Your opening sentence is something I'm keen to adhere to - while it would be horrendous to teach _everything_ at once, I don't want to simplify to the extent that what I'm saying is wrong or bad practice. But I have a practical problem with your advice to not catch exceptions in that the IDE (IntelliJ) doesn't like that.  I shall need to experiment a bit more to see how strongly it objects, but in the meantime is there an easy way to say to Java "Just fail on all exceptions"?  
  > **username_4**: I agree: you don't necessarily need to use `try`/`catch` in the caller. This makes it both good and fairly easy, if you type methods `throws Exception` and teach students to `throw Exception("description of contract violation")`. The other way to simplify is to not worry too much about the type of exceptions. Your testing harness boilerplate can use `try`/`catch` or proper JUnit assertions, as applicable (students need not understand it fully right off the bat). That said, for many data structures it's acceptable to return `null` when lookup operations fail as many Java util collections do.  
  > **username_5**: @username_4 Yes, and IMHO it all depends on the contract that you have in mind, whether you expect some element not to exist, and include that in the contract. Or you insist that an object is found, and then not finding one is a failure. It's like the distinction between the words "search" and "find".  
  > **username_0**: I _almost_ accepted this one because your phrase "Don't catch exceptions" prompted an important shift in my thinking, and today my students showed how to get our IDE to stop complaining that I wasn't `try/catch`ing the exceptions (by adding `throws Exception` to the `main` declaration).  So thank you for that phrase!  
  
  ---
  
  ### Answer by username_1 on 2023-11-19. Score: 2
  
  You may need to teach this concept, but I'd do it at the point it becomes be best option. If things can fail, some sort of test or similar action is needed.
  
  For a list of objects, one can return null in many cases (unless null is a valid value). If a list contains non-negatives you can return -1, say, and test for it. This implies you have already taught other structured statements, such as if-else, etc. So, such statements are no longer a mystery to them.
  
  After you have done this a few times you can discuss the more subtle cases.
  
  First, show them a program that fails (crashes) due to this sort of situation. Then show how a program can recover from such a situation with a try-catch. It shouldn't need to be a big step.
  
  First examples might do no more than give better error messages before halting. Once the structure and execution are clear you can do more with actual recovery.
  
  And, Python can *raise* and catch exceptions also, in which case you might draw on their knowledge of that language.
  
  > **Comments:**
  > **username_0**: Thank you.  Returning `null` sounds like a reasonable placeholder (which is what I'm after).  You're right to assume that they know about the various structured statements, and while some might have met python's exception handling then I don't want to assume it and also don't want to introduce too many things in one go.  At this stage, we're not writing complicated programs, so just testing for `null` is fine.  
  > **username_3**: null and un-exceptional exceptions, are two of the biggest mistakes in programming. Does Java have types that can be value or error (but nothing else)? I think it may be possible to make a type with `class`.  
  
  ---
  
  ### Answer by username_3 on 2023-11-26. Score: 1
  
  In Java and many other languages that followed it, Exceptions are un-exceptional: e.g. it is not exceptional to get to the end of a file.
  
  Your example of removing an item from an empty list, is a contract pre-condition violation. Add a method `bool list.is_empty()`. Then a pre-condition `!is_empty()`. If the precondition is not met, then throw an error. Don't catch it, as it indicates a programming error: the program should have checked the pre-condition.
  
  More importantly, are exceptions in the syllabus?
  
  
  ---
  
  ### Answer by username_3 on 2023-11-26. Score: 1
  
  Create a type value or error (but nothing else: so not object)
  
  e.g.
  
  ```
  class value_or_error {
      private int _value;
      private bool _is_error;
  
      public bool is_error(){
         return _is_error();
      }
      public int value() {
         if _is_error then throw;
         return _value;
      }
  }
  
  ```
  
  Sorry if it does not compile (no javac installed)
  
  
  ---
  
  