<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>neilmadden.blog</title>
  <subtitle>Browse aymeric&#39;s, an independent, searchable archive of readable snapshots from followed feeds, preserved in Git with aggr.</subtitle>
  <id>https://aggr.aymericbeaumet.com/sources/neilmadden.blog/</id>
  <link rel="alternate" type="text/html" href="https://aggr.aymericbeaumet.com/sources/neilmadden.blog/"/>
  <link rel="self" type="application/atom+xml" href="https://aggr.aymericbeaumet.com/sources/neilmadden.blog/atom.xml"/>
  <updated>2026-10-18T14:47:37+00:00</updated>
  <author>
    <name>aymeric&#39;s</name>
  </author>
  <generator version="2.0.0" uri="https://github.com/aymericbeaumet/aggr">aggr</generator>
  <entry>
    <id>urn:aggr:item:5668ad42f0b36edc523948ff9f4038899dfdb2dd</id>
    <title type="text">Java sealed classes and exhaustive pattern matching</title>
    <link rel="alternate" type="text/html" href="https://aggr.aymericbeaumet.com/items/hnrss-org/2026-10-18-java-sealed-classes-and-exhaustive-pattern-matching/"/>
    <link rel="via" type="text/html" href="https://neilmadden.blog/2026/04/24/java-sealed-classes-and-exhaustive-pattern-matching/"/>
    <published>2026-10-18T14:47:37+00:00</published>
    <updated>2026-10-18T14:47:37+00:00</updated>
    <author>
      <name>hnisjafx40</name>
    </author>
    <category term="news"/>
    <source>
      <title>Hacker News: Front Page</title>
    </source>
    <summary type="text">Java 17 introduced sealed classes, which allow you to explicitly list the allowed sub-types of an interface or base class. For example, here’s a toy example using a sealed interface and records (inner classes are implicitly added to the…</summary>
    <content type="html">&lt;p&gt;Java 17 introduced &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://openjdk.org/jeps/409&quot;&gt;sealed classes&lt;/a&gt;, which allow you to explicitly list the allowed sub-types of an interface or base class. For example, here’s a toy example using a sealed interface and records (inner classes are implicitly added to the permitted sub-types if an explicit list is not given):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Java&quot;&gt;&lt;span class=&quot;syntax-source syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;&lt;span class=&quot;syntax-storage syntax-modifier syntax-java&quot;&gt;public&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;d &lt;span class=&quot;syntax-meta syntax-class syntax-identifier syntax-java&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-java&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;syntax-entity syntax-name syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-class syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;
    record &lt;span class=&quot;syntax-meta syntax-method syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-identifier syntax-java&quot;&gt;&lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-constructor syntax-java&quot;&gt;TypeA&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;implements &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-static syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
    record &lt;span class=&quot;syntax-meta syntax-method syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-identifier syntax-java&quot;&gt;&lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-constructor syntax-java&quot;&gt;TypeB&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;implements &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-static syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;

    &lt;span class=&quot;syntax-storage syntax-modifier syntax-java&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-method syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-identifier syntax-java&quot;&gt;&lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-java&quot;&gt;of&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;syntax-variable syntax-parameter syntax-java&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-method syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-block syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;case&lt;/span&gt; “&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;A&lt;/span&gt;” &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-java&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-keyword syntax-operator syntax-comparison syntax-java&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-instantiation syntax-java&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-new syntax-java&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;TypeA&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;case&lt;/span&gt; “&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;B&lt;/span&gt;” &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-java&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-keyword syntax-operator syntax-comparison syntax-java&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-instantiation syntax-java&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-new syntax-java&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;TypeB&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;syntax-storage syntax-modifier syntax-java&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-java&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-keyword syntax-operator syntax-comparison syntax-java&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-control syntax-catch-exception syntax-java&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-instantiation syntax-java&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-new syntax-java&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;IllegalArgumentException&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are familiar with functional programming languages with algebraic datatypes, you can view this as similar to a datatype declaration in Haskell or ML:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Haskell&quot;&gt;&lt;span class=&quot;syntax-source syntax-haskell&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-other syntax-haskell&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-other syntax-haskell&quot;&gt;SealedType&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-haskell&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-other syntax-haskell&quot;&gt;TypeA&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-haskell&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-other syntax-haskell&quot;&gt;TypeB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then use this in a simple Main class:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Java&quot;&gt;&lt;span class=&quot;syntax-source syntax-java&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-primitive syntax-java&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-function-call syntax-java&quot;&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-java&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;syntax-storage syntax-modifier syntax-array syntax-java&quot;&gt;[]&lt;/span&gt; args&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-block syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;
    var val &lt;span class=&quot;syntax-meta syntax-assignment syntax-rhs syntax-java&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-operator syntax-assignment syntax-java&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-dot syntax-java&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-java&quot;&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-java&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;args[&lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-java&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-dot syntax-java&quot;&gt;.&lt;/span&gt;out&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-dot syntax-java&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-java&quot;&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-java&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-invalid syntax-illegal syntax-stray-terminator-end&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-dot syntax-java&quot;&gt;.&lt;/span&gt;TypeA&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-anonymous syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-anonymous syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-anonymous syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-function syntax-anonymous syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-function syntax-anonymous syntax-java&quot;&gt;-&amp;gt;&lt;/span&gt; “&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;A&lt;/span&gt;”&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-dot syntax-java&quot;&gt;.&lt;/span&gt;TypeB&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-anonymous syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-anonymous syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-anonymous syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-function syntax-anonymous syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-function syntax-anonymous syntax-java&quot;&gt;-&amp;gt;&lt;/span&gt; “&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;B&lt;/span&gt;”&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-invalid syntax-illegal syntax-stray-parens-end&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OK, not so exciting. But one thing to note here is that we didn’t have to add a &lt;code&gt;default&lt;/code&gt; clause to the switch expression in our main method. This is because sealed classes (and enums) enable &lt;em&gt;exhaustiveness checking&lt;/em&gt;: the compiler knows exactly what the possible cases are, and so can check if you have covered them all. If you have, then you don’t need a &lt;code&gt;default&lt;/code&gt; clause. If you forget one (and don’t have a default clause), then you get a compile-time error.&lt;/p&gt;
&lt;p&gt;This is great when you want to ensure that all uses of some type do cover all of the cases, but it does introduce a new type of breaking change: adding a new sub-type to a sealed class/interface may break consumers of that code. For example, adding a new &lt;code&gt;TypeC&lt;/code&gt; case to our example will cause the main method to fail to compile due to the missing case. So if you export a sealed type in your API then adding a new subtype is a breaking change that would require a major version bump (if you’re following SemVer).&lt;/p&gt;
&lt;h2&gt;Compile-time or runtime error?&lt;/h2&gt;
&lt;p&gt;Although Java will produce a compile-time error for a non-exhaustive switch when you compile the consumer (main in this case), it cannot do so if the consumer is not recompiled when the sealed type changes. For example, suppose that we extend our SealedType with another case:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Java&quot;&gt;&lt;span class=&quot;syntax-source syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;&lt;span class=&quot;syntax-storage syntax-modifier syntax-java&quot;&gt;public&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-class syntax-java&quot;&gt;d &lt;span class=&quot;syntax-meta syntax-class syntax-identifier syntax-java&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-java&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;syntax-entity syntax-name syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-class syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;
    record &lt;span class=&quot;syntax-meta syntax-method syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-identifier syntax-java&quot;&gt;&lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-constructor syntax-java&quot;&gt;TypeA&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;implements &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-static syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
    record &lt;span class=&quot;syntax-meta syntax-method syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-identifier syntax-java&quot;&gt;&lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-constructor syntax-java&quot;&gt;TypeB&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;implements &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-static syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
    record &lt;span class=&quot;syntax-meta syntax-method syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-identifier syntax-java&quot;&gt;&lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-constructor syntax-java&quot;&gt;TypeC&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;implements &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-static syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;

    &lt;span class=&quot;syntax-storage syntax-modifier syntax-java&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;SealedType&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-method syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-identifier syntax-java&quot;&gt;&lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-java&quot;&gt;of&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-method syntax-parameters syntax-java&quot;&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;syntax-variable syntax-parameter syntax-java&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-method syntax-body syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-block syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-java&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;case&lt;/span&gt; “&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;A&lt;/span&gt;” &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-java&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-keyword syntax-operator syntax-comparison syntax-java&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-instantiation syntax-java&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-new syntax-java&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;TypeA&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;case&lt;/span&gt; “&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;B&lt;/span&gt;” &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-java&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-keyword syntax-operator syntax-comparison syntax-java&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-instantiation syntax-java&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-new syntax-java&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;TypeB&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;syntax-keyword syntax-control syntax-java&quot;&gt;case&lt;/span&gt; “&lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;C&lt;/span&gt;” &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-java&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-keyword syntax-operator syntax-comparison syntax-java&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-instantiation syntax-java&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-new syntax-java&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;TypeC&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;syntax-storage syntax-modifier syntax-java&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-java&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;syntax-keyword syntax-operator syntax-comparison syntax-java&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-control syntax-catch-exception syntax-java&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-instantiation syntax-java&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-new syntax-java&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-class syntax-java&quot;&gt;IllegalArgumentException&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-parens syntax-java&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-begin syntax-java&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parens syntax-end syntax-java&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-java&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-java&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we just recompiled SealedType.java and don’t recompile Main, then we end up with a &lt;strong&gt;runtime exception&lt;/strong&gt; if we trigger the new case:&lt;/p&gt;
&lt;p&gt;Here we have the new &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/MatchException.html&quot;&gt;MatchException&lt;/a&gt; being thrown. The Javadoc notes this potential issue with separate compilation, and also some corner-cases with nulls in patterns. So even if you were hoping that using sealed classes would statically ensure that you update all consumers when a new case is added, this is not the case unless you recompile everything.&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I think for me the conclusion is that sealed types are probably most useful &lt;em&gt;within&lt;/em&gt; the implementation of a component, and are less useful when exposed in the public API that a component offers to other components (eg a library). For internal use, where you typically &lt;em&gt;are&lt;/em&gt; going to recompile everything together, you get the nice properties of exhaustiveness checking and higher compile-time safety guarantees. But when used across module boundaries, you may just be introducing new ways to break code, often only detectable at runtime.&lt;/p&gt;
&lt;p&gt;(I discovered these subtleties when reviewing the &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://openjdk.org/jeps/524&quot;&gt;preview support for PEM-encoded cryptographic objects&lt;/a&gt;, which makes exactly this mistake of baking a sealed interface into a public API and recommend clients to pattern match against that type. A predict a very high chance of breakage if they ever want to add a new case).&lt;/p&gt;
</content>
  </entry>
</feed>
