{"id":15069335,"url":"https://github.com/xyzsd/dichotomy","last_synced_at":"2025-07-26T00:39:43.727Z","repository":{"id":207459748,"uuid":"500945552","full_name":"xyzsd/dichotomy","owner":"xyzsd","description":"Result, Either, Try, and Maybe monadic types for Java","archived":false,"fork":false,"pushed_at":"2025-05-07T03:13:12.000Z","size":335,"stargazers_count":35,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-07T03:25:14.113Z","etag":null,"topics":["adt","algebraic-data-types","either","either-monad","error-handling","java","jdk","jvm","maybe-monad","monads","railway-oriented-programming","result","result-monad","result-type","sealed-class","sum-types","try","try-monad","types"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xyzsd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-06-07T17:45:02.000Z","updated_at":"2025-05-07T03:13:16.000Z","dependencies_parsed_at":"2024-05-05T06:24:08.255Z","dependency_job_id":"5872403e-b93f-452e-9f17-8a06e5399cd0","html_url":"https://github.com/xyzsd/dichotomy","commit_stats":null,"previous_names":["xyzsd/dichotomy"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/xyzsd/dichotomy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xyzsd%2Fdichotomy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xyzsd%2Fdichotomy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xyzsd%2Fdichotomy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xyzsd%2Fdichotomy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xyzsd","download_url":"https://codeload.github.com/xyzsd/dichotomy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xyzsd%2Fdichotomy/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267093930,"owners_count":24034958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-25T02:00:09.625Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adt","algebraic-data-types","either","either-monad","error-handling","java","jdk","jvm","maybe-monad","monads","railway-oriented-programming","result","result-monad","result-type","sealed-class","sum-types","try","try-monad","types"],"created_at":"2024-09-25T01:41:52.486Z","updated_at":"2025-07-26T00:39:43.717Z","avatar_url":"https://github.com/xyzsd.png","language":"Java","readme":"[![Java CI with Gradle](https://github.com/xyzsd/dichotomy/actions/workflows/gradle.yml/badge.svg)](https://github.com/xyzsd/dichotomy/actions/workflows/gradle.yml)\n\n# dichotomy\nSealed monads for Java.\n\nGenerally these types are used to return one of two values, such as success or failure. \n\nAll types are sealed (Sum types), and can be used in `switch` expressions and with\npattern matching.\n\n`dichotomy` is svelte, at about 48 KB.\n\n\n\n### `Either`:\nA general immutable type that can only be *either* one of two types.\nThe types are called `Left\u003cL\u003e` and `Right\u003cR\u003e`. By convention, the Left type\nindicates failure, while the Right type indicates success.\n\n### `Result`:\nSimilar to an `Either`, but with success/failure semantics more clearly defined.\nAn `OK\u003cV\u003e` Result indicates success, and an `Err\u003cE\u003e` Result indicates failure. Failure\ntypes *do not* need to be Exceptions. \n\n ```java \n\nResult\u003cDouble,String\u003e result = Result.\u003cInteger, String\u003eofOK(3828)  // returns an OK\u003cInteger\u003e\n        .map(x -\u003e x*10.0)        // map to Result\u003cDouble,String\u003e, after multiplying x 10\n        .match(System.out::println)     // print \"38280.0\" to console\n        .matchErr(System.err::println);   // ignored, as this is an OK\n\nswitch(result) {\n    case OK\u003cDouble,String\u003e ok -\u003e System.out.println(\"value ok! value: \"+ok.value());\n    case Err\u003cDouble,String\u003e err -\u003e System.err.println(err.value());\n}\n\n// JDK 21+\nswitch(result) {\n    case OK(Double x) when x \u003e 0 -\u003e System.out.println(\"positive\");\n    case OK(Double x) -\u003e System.out.println(\"0 or negative\");\n    case Err(String s) -\u003e System.err.println(s);\n}\n\n// anotherResult here will be an Err\u003cString\u003e\nResult\u003cDouble,String\u003e anotherResult = Result.\u003cInteger, String\u003eofErr(\"Insufficient entropy\")\n          .map(x -\u003e x*10.0 )       // ignored, as this is an Err\n          .match(System.out::println)     // ignored, as this is an Err\n          .matchErr(System.err::println);  // \"Insufficient entropy\" printed to System.err\n```\n\n  \n### `Try`:\nA specialized type of `Result`. A `Try` wraps a function or block; if \nsuccessful, a `Success` Try is returned; otherwise, a `Failure` Try containing\nan Exception is returned. Intermediate operations which return Trys will also\ncatch generated Exceptions.\n\n```java\n\nfinal Try\u003cInteger\u003e result = Try.ofSuccess( 777 )\n        .map( i -\u003e i * 1000 )           // results in a Try\u003cInteger\u003e with a value of 777000\n        .exec( System.out::println )    // prints \"777000\"\n        .map( i -\u003e i / 0 )              // the ArithmeticException is caught as a Try.Failure\n        .exec( System.out::println );   // does not exec() because we are a Failure\n\n// prints \"ERROR: java.lang.ArithmeticException: / by zero\"\nswitch(result) {\n        case Success(Integer i) -\u003e System.out.printf(\"Operation completed successfully. Value: %d\\n\", i);\n        case Failure(Throwable t) -\u003e System.err.printf(\"ERROR: %s\\n\", t);\n}\n  \n\n```\n\n### `Maybe`:\nAnalogous to the JDK `Optional` type, but sealed so it may be used in `switch` \nstatements and with pattern matching.  \n\n\n## Updates \n\nAs always, any feature requests or improvements are always welcome.\n\n### v2.0_experimental branch (May 2025)\nThis branch targets JDK 24 with JEP-485 (Stream Gatherers) finalization. \n\nAn experimental `ResultStream\u003cV,E\u003e` which can directly operate on `Results` is the new feature, \nusing gatherers defined in `ResultGatherers`. \n\n\n### Release 1.1 (May 2025)\nTarget remains JDK 21.\n\n[JSpecify](https://jspecify.dev/) replaces JSR-305 nullness annotations. \n\nThis release also adds `Result::merge` which simplifies reduction operations on `Result` streams \n(see method documentation and tests for examples).\n\n\n### Release 1.0 (January 2024)\nRefactored and improved from the original version. \n\nHandling exceptions is substantially better with the new\n`Try` type (a specialized type of `Result`), which also\nsupports the try-with-resources pattern.\n\nSome usage examples are now included... though additional\nillustrative examples should be provided!\n\nDocumentation\n-------------\n[Available online][doc_online] or by [download][doc_download].\n\n\nDownload\n--------\ndepend via Maven:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.xyzsd\u003c/groupId\u003e\n  \u003cartifactId\u003edichotomy\u003c/artifactId\u003e\n  \u003cversion\u003e1.1\u003c/version\u003e\n  \u003ctype\u003emodule\u003c/type\u003e\n\u003c/dependency\u003e\n```\n\nor Gradle:\n```kotlin\nimplementation(\"net.xyzsd:dichotomy:1.1\")\n```\n\nor [download](https://github.com/xyzsd/dichotomy/releases/tag/1.0) from GitHub.\n\nLicense\n-------\nCopyright 2022-2025, xyzsd\n\nMany thanks to [@fdelsert](https://github.com/fdelsert) for\nsuggestions and improvements leading to the 1.0 release.\n\nLicensed under either of:\n\n* Apache License, Version 2.0\n  (see LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)\n* MIT license\n  (see LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n\n\n[doc_online]: https://javadoc.io/doc/net.xyzsd/dichotomy/1.1/index.html\n[doc_download]: https://github.com/xyzsd/dichotomy/releases/download/1.1/dichotomy-javadoc-1.1-javadoc.jar\n\n","funding_links":[],"categories":["\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxyzsd%2Fdichotomy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxyzsd%2Fdichotomy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxyzsd%2Fdichotomy/lists"}