{"id":3655890,"date":"2023-08-17T08:00:07","date_gmt":"2023-08-17T12:00:07","guid":{"rendered":"https:\/\/spin.atomicobject.com\/?p=3655890"},"modified":"2023-08-16T14:01:22","modified_gmt":"2023-08-16T18:01:22","slug":"java-sealed-interface","status":"publish","type":"post","link":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/","title":{"rendered":"Java&#8217;s Discriminated Union: Sealed Interfaces"},"content":{"rendered":"<p>Discriminated unions are a powerful data structure supported in many programming languages. They provide the ability to define a complex, defined data structure of types with exhaustive type checking and pattern matching. Simply put, a <a href=\"https:\/discriminated-unions-typescript-project\/\">discriminated union<\/a> limits an object&#8217;s structure to a defined set of possible types.<\/p>\n<p>In Typescript, using a discriminated union would look something like this:<\/p>\n<pre><code class=\"language-typescript\">\ntype Dog = {\n    breed: \"dog\";\n    furColor: string;\n};\n\ntype Cat = {\n    breed: \"cat\";\n    eyeColor: string;\n};\n\ntype Animal = Dog | Cat;\n\nconst foobar = (animal: Animal): string =&gt; {\n    switch (animal.breed) {\n        case \"dog\":\n            return `It's a dog with ${animal.furColor} fur!`;\n        case \"cat\":\n            return `It's a cat with ${animal.eyeColor} eyes!`;\n    }\n};\n<\/code><\/pre>\n<h2>Can we do this in Java?<\/h2>\n<p>For a long time, the answer to this question was no. Java did not support providing a defined set of type and performing exhaustive operations on an object. However, Java 17 now has its own way to emulate this behavior with the additions of sealed interfaces\/classes and pattern matching.<\/p>\n<p>Previously, a switch statement across an interface would look similar to this:<\/p>\n<pre><code class=\"language-java\">\npublic interface Animal {\n    String breed();\n}\n\nclass Dog implements Animal {\n    @Override\n    public String breed() {\n        return \"dog\";\n    }\n\n    public String bark() {\n        return \"woof\";\n    }\n}\n\nclass Cat implements Animal {\n    @Override\n    public String breed() {\n        return \"cat\";\n    }\n\n    public String meow() {\n        return \"meow\";\n    }\n}\n\nclass AnimalFactory {\n    public static String get(Animal animal) {\n        return switch (animal.breed()) {\n            case \"dog\" -&gt; \"It's a dog!\";\n            case \"cat\" -&gt; \"It's a cat!\";\n            default -&gt; throw new IllegalStateException(\"Unexpected value: \" + animal.breed());\n        };\n    }\n}\n<\/code><\/pre>\n<p>The issue is the lack of strict typing and exhaustive checking around the cases of the switch statement. Without strict typing, the programmer must rely entirely on their knowledge of what values the field can be equal to. The compiler provides no support for what the possible values are for <code>breed()<\/code>and if any additional classes implement Animal. For instance, if I added a class Lizard with that returned <code>lizard<\/code> when calling <code>breed()<\/code>, the code would compile with no errors.<\/p>\n<p>This may not seem like an issue for such a small use case. However, when working on a large codebase, making the change in every case where this switch statement occurs can be a lot. Additionally, to access any of the methods on the class implementations, we must cast the class ourselves.<\/p>\n<h2>Here&#8217;s how to do this in modern Java.<\/h2>\n<p>With modern Java, this switch statement becomes much easier to handle.<\/p>\n<pre><code class=\"language-java\">\npublic sealed interface Animal permits Dog, Cat {\n    String breed();\n}\n\nfinal class Dog implements Animal {\n    @Override\n    public String breed() {\n        return \"dog\";\n    }\n\n    public String bark() {\n        return \"woof\";\n    }\n}\n\nfinal class Cat implements Animal {\n    @Override\n    public String breed() {\n        return \"cat\";\n    }\n\n    public String meow() {\n        return \"meow\";\n    }\n}\n\nclass AnimalFactory {\n    public static String get(Animal animal) {\n        return switch (animal) {\n            case Dog dog -&gt; String.format(\"Its a dog that barks %s\", dog.bark());\n            case Cat cat -&gt; String.format(\"Its a cat that meows %s\", cat.meow());\n        };\n    }\n}\n<\/code><\/pre>\n<p>By turning <code>Animal<\/code> into a sealed interface that permits Dog and Cat, we are telling the compiler that the only classes allowed to implement <code>Animal<\/code> are <code>Dog<\/code> and <code>Cat<\/code>. This lets us perform a switch statement on the <code>Animal<\/code> object itself, with the cases being each of the interface implementations. Coupled with pattern matching, each case automatically and safely casts the object as its respective class implementation, allowing us to access the other methods in the class.<\/p>\n<p>Additionally, there is no need for a default case. We&#8217;re switching on the type, and there is a defined set of possible types. That means no case will ever fall through to the default. If any new class becomes permitted as an implementation of the <code>Animal<\/code> interface, then the Java compiler will force a new case to be added for the new class.<\/p>\n<h2>Pattern Matching + Sealed Interface<\/h2>\n<p>Using pattern matching in conjunction with sealed interfaces, Java developers can leverage the power of switch statements to handle different cases based on the specific implementations of the sealed interface. This way, each case automatically performs a safe cast, enabling easy access to additional methods and properties specific to each implementation.<\/p>\n<p>Modern Java combines sealed interfaces, pattern matching, and strict typing. That provides a more concise, maintainable, and predictable way to work with complex types and perform exhaustive operations. In turn, this enhances code readability, reduces the risk of errors, and facilitates better code maintenance and scalability.<\/p>\n<p>As programming languages evolve, they&#8217;re adopting powerful language features like discriminated unions in TypeScript and sealed interfaces in Java. Those features enable developers to write more expressive and robust code, pushing the boundaries of what we can achieve in software development.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Discriminated unions are a powerful data structure supported in many programming languages. They provide the ability to define a complex, defined data structure of types with exhaustive type checking and pattern matching. Simply put, a discriminated union limits an object&#8217;s structure to a defined set of possible types. In Typescript, using a discriminated union would [&hellip;]<\/p>\n","protected":false},"author":631,"featured_media":3656623,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1764],"tags":[564,2319],"series":[],"class_list":["post-3655890","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java-dev","tag-java","tag-typescript"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Java&#039;s Discriminated Union and the Sealed Interface<\/title>\n<meta name=\"description\" content=\"The Sealed Interface is a new addition in Java 17 that allows developers to emulate the discriminated union data structure.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/spin.atomicobject.com\/java-sealed-interface\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Java&#039;s Discriminated Union and the Sealed Interface\" \/>\n<meta property=\"og:description\" content=\"The Sealed Interface is a new addition in Java 17 that allows developers to emulate the discriminated union data structure.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/spin.atomicobject.com\/java-sealed-interface\/\" \/>\n<meta property=\"og:site_name\" content=\"Atomic Spin\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/atomicobject\" \/>\n<meta property=\"article:published_time\" content=\"2023-08-17T12:00:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/java-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"400\" \/>\n\t<meta property=\"og:image:height\" content=\"215\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Matthew Harper\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@atomicobject\" \/>\n<meta name=\"twitter:site\" content=\"@atomicobject\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matthew Harper\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/\"},\"author\":{\"name\":\"Matthew Harper\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/person\\\/df49a130cf0154c5093ae1ff9a3b9df6\"},\"headline\":\"Java&#8217;s Discriminated Union: Sealed Interfaces\",\"datePublished\":\"2023-08-17T12:00:07+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/\"},\"wordCount\":560,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/atomicobject.com\\\/\"},\"image\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/java-logo.jpg\",\"keywords\":[\"java\",\"typescript\"],\"articleSection\":[\"Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/\",\"name\":\"Java's Discriminated Union and the Sealed Interface\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/java-logo.jpg\",\"datePublished\":\"2023-08-17T12:00:07+00:00\",\"description\":\"The Sealed Interface is a new addition in Java 17 that allows developers to emulate the discriminated union data structure.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/java-sealed-interface\\\/#primaryimage\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/java-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/java-logo.jpg\",\"width\":400,\"height\":215,\"caption\":\"Java's Discriminated Union: The Sealed Interface\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#website\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/\",\"name\":\"Atomic Spin\",\"description\":\"Atomic Object\u2019s blog on everything we find fascinating.\",\"publisher\":{\"@id\":\"https:\\\/\\\/atomicobject.com\\\/\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/spin.atomicobject.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#organization\",\"name\":\"Atomic Object\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/AO-Logo-Emblem-Color.png\",\"contentUrl\":\"https:\\\/\\\/spin.atomicobject.com\\\/wp-content\\\/uploads\\\/AO-Logo-Emblem-Color.png\",\"width\":258,\"height\":244,\"caption\":\"Atomic Object\"},\"image\":{\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/atomicobject\",\"https:\\\/\\\/x.com\\\/atomicobject\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/spin.atomicobject.com\\\/#\\\/schema\\\/person\\\/df49a130cf0154c5093ae1ff9a3b9df6\",\"name\":\"Matthew Harper\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fd32cb575570edd358f0864618342d902d7a4346d16a1eb041c4c22952ae9c2c?s=96&d=blank&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fd32cb575570edd358f0864618342d902d7a4346d16a1eb041c4c22952ae9c2c?s=96&d=blank&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fd32cb575570edd358f0864618342d902d7a4346d16a1eb041c4c22952ae9c2c?s=96&d=blank&r=pg\",\"caption\":\"Matthew Harper\"},\"description\":\"Software Consultant and Developer, thinking critically to bring my client\u2019s ideas to life.\",\"sameAs\":[\"https:\\\/\\\/atomicobject.com\"],\"url\":\"https:\\\/\\\/spin.atomicobject.com\\\/author\\\/matthew-harper\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Java's Discriminated Union and the Sealed Interface","description":"The Sealed Interface is a new addition in Java 17 that allows developers to emulate the discriminated union data structure.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/","og_locale":"en_US","og_type":"article","og_title":"Java's Discriminated Union and the Sealed Interface","og_description":"The Sealed Interface is a new addition in Java 17 that allows developers to emulate the discriminated union data structure.","og_url":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/","og_site_name":"Atomic Spin","article_publisher":"https:\/\/www.facebook.com\/atomicobject","article_published_time":"2023-08-17T12:00:07+00:00","og_image":[{"width":400,"height":215,"url":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/java-logo.jpg","type":"image\/jpeg"}],"author":"Matthew Harper","twitter_card":"summary_large_image","twitter_creator":"@atomicobject","twitter_site":"@atomicobject","twitter_misc":{"Written by":"Matthew Harper","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/#article","isPartOf":{"@id":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/"},"author":{"name":"Matthew Harper","@id":"https:\/\/spin.atomicobject.com\/#\/schema\/person\/df49a130cf0154c5093ae1ff9a3b9df6"},"headline":"Java&#8217;s Discriminated Union: Sealed Interfaces","datePublished":"2023-08-17T12:00:07+00:00","mainEntityOfPage":{"@id":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/"},"wordCount":560,"commentCount":0,"publisher":{"@id":"https:\/\/atomicobject.com\/"},"image":{"@id":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/#primaryimage"},"thumbnailUrl":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/java-logo.jpg","keywords":["java","typescript"],"articleSection":["Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/spin.atomicobject.com\/java-sealed-interface\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/","url":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/","name":"Java's Discriminated Union and the Sealed Interface","isPartOf":{"@id":"https:\/\/spin.atomicobject.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/#primaryimage"},"image":{"@id":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/#primaryimage"},"thumbnailUrl":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/java-logo.jpg","datePublished":"2023-08-17T12:00:07+00:00","description":"The Sealed Interface is a new addition in Java 17 that allows developers to emulate the discriminated union data structure.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/spin.atomicobject.com\/java-sealed-interface\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/spin.atomicobject.com\/java-sealed-interface\/#primaryimage","url":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/java-logo.jpg","contentUrl":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/java-logo.jpg","width":400,"height":215,"caption":"Java's Discriminated Union: The Sealed Interface"},{"@type":"WebSite","@id":"https:\/\/spin.atomicobject.com\/#website","url":"https:\/\/spin.atomicobject.com\/","name":"Atomic Spin","description":"Atomic Object\u2019s blog on everything we find fascinating.","publisher":{"@id":"https:\/\/atomicobject.com\/"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/spin.atomicobject.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/spin.atomicobject.com\/#organization","name":"Atomic Object","url":"https:\/\/spin.atomicobject.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/spin.atomicobject.com\/#\/schema\/logo\/image\/","url":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/AO-Logo-Emblem-Color.png","contentUrl":"https:\/\/spin.atomicobject.com\/wp-content\/uploads\/AO-Logo-Emblem-Color.png","width":258,"height":244,"caption":"Atomic Object"},"image":{"@id":"https:\/\/spin.atomicobject.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/atomicobject","https:\/\/x.com\/atomicobject"]},{"@type":"Person","@id":"https:\/\/spin.atomicobject.com\/#\/schema\/person\/df49a130cf0154c5093ae1ff9a3b9df6","name":"Matthew Harper","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/fd32cb575570edd358f0864618342d902d7a4346d16a1eb041c4c22952ae9c2c?s=96&d=blank&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/fd32cb575570edd358f0864618342d902d7a4346d16a1eb041c4c22952ae9c2c?s=96&d=blank&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/fd32cb575570edd358f0864618342d902d7a4346d16a1eb041c4c22952ae9c2c?s=96&d=blank&r=pg","caption":"Matthew Harper"},"description":"Software Consultant and Developer, thinking critically to bring my client\u2019s ideas to life.","sameAs":["https:\/\/atomicobject.com"],"url":"https:\/\/spin.atomicobject.com\/author\/matthew-harper\/"}]}},"_links":{"self":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/posts\/3655890","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/users\/631"}],"replies":[{"embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/comments?post=3655890"}],"version-history":[{"count":0,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/posts\/3655890\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/media\/3656623"}],"wp:attachment":[{"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/media?parent=3655890"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/categories?post=3655890"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/tags?post=3655890"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/spin.atomicobject.com\/wp-json\/wp\/v2\/series?post=3655890"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}