{"id":22041781,"url":"https://github.com/glenkpeterson/paguro","last_synced_at":"2025-05-15T12:02:21.075Z","repository":{"id":13764503,"uuid":"16459315","full_name":"GlenKPeterson/Paguro","owner":"GlenKPeterson","description":"Generic, Null-safe, Immutable Collections and Functional Transformations for the JVM","archived":false,"fork":false,"pushed_at":"2024-12-30T22:17:19.000Z","size":4216,"stargazers_count":315,"open_issues_count":11,"forks_count":26,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-05-15T12:02:02.683Z","etag":null,"topics":["clojure","functional-transformations","immutability","immutable-collections","java","jvm","kotlin","null-safety","persistentvector","rrb-tree","stream","transformations"],"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/GlenKPeterson.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGE_LOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","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}},"created_at":"2014-02-02T17:44:36.000Z","updated_at":"2025-05-03T12:42:20.000Z","dependencies_parsed_at":"2024-11-30T12:09:19.214Z","dependency_job_id":"d436c37f-f981-467c-8fbf-dd42ac810d1a","html_url":"https://github.com/GlenKPeterson/Paguro","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GlenKPeterson%2FPaguro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GlenKPeterson%2FPaguro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GlenKPeterson%2FPaguro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GlenKPeterson%2FPaguro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GlenKPeterson","download_url":"https://codeload.github.com/GlenKPeterson/Paguro/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337612,"owners_count":22054253,"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","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":["clojure","functional-transformations","immutability","immutable-collections","java","jvm","kotlin","null-safety","persistentvector","rrb-tree","stream","transformations"],"created_at":"2024-11-30T12:09:13.790Z","updated_at":"2025-05-15T12:02:21.001Z","avatar_url":"https://github.com/GlenKPeterson.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Hermit Crab](HermitCrabByRushen.jpg)\n\n[![Maven Central](https://img.shields.io/maven-central/v/org.organicdesign/Paguro.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22org.organicdesign%22%20AND%20a:%22Paguro%22)\n[![javadoc](https://javadoc.io/badge2/org.organicdesign/Paguro/javadoc.svg)](https://javadoc.io/doc/org.organicdesign/Paguro)\n[![Build Status](https://travis-ci.org/GlenKPeterson/Paguro.svg?branch=master)](https://travis-ci.org/GlenKPeterson/Paguro)\n[![codecov](https://codecov.io/gh/GlenKPeterson/Paguro/branch/master/graph/badge.svg)](https://codecov.io/gh/GlenKPeterson/Paguro)\n[![Google group : Email List](https://img.shields.io/badge/Google%20Group-Email%20List-blue.svg)](https://groups.google.com/d/forum/paguro)\n\n# Why Use Paguro?\n\nPaguro is designed to:\n 1. Make Functional Programming simpler and easier in Java.\n 2. Decrease the number of things you need to think about when coding.\n\nRemoving distractions leaves you more energy for creativity and problem-solving.\nPaguro lets you forget about:\n\n * Potential modifications to shared collections (immutable collections are safe to share)\n * The cost of adding items to an unmodifiable collection (immutable collections support extremely lightweight modified copies)\n * Which collections are modifiable (your compiler knows)\n * Arrays vs. collections (use `xformArray(myArray)` to encapsulate arrays)\n * Primitives vs. boxed objects (Don't use primitives - generics can't handle them anyway)\n * Checked exceptions in lambdas (Paguro accepts them without complaint)\n * Null pointer exceptions\n\nKotlin fixes almost all these issues too, but if you're stuck in Java, Paguro is a great solution.\n\n# What's in Paguro?\nType-safe, null-safe versions of Clojure's immutable/persistent collections, an immutable alternative to Java 8 Streams that handles checked exceptions in lambdas, and other tools to make functional programming in Java easier.\n\n# Why is it called Paguro?\n\nPaguro is short for the Latin \"Paguroidea\" - the name of the Hermit Crab superfamily in Biology.  These collections grow by adding a new shell, leaving the insides the same, much the way [Hermit Crabs trade up to a new shell when they grow](https://www.youtube.com/watch?v=f1dnocPQXDQ).\n\n# Specific Features\n\n* **Immutable collections** [api](https://javadoc.io/doc/org.organicdesign/Paguro/latest/org/organicdesign/fp/collections/package-summary.html) / [src](src/main/java/org/organicdesign/fp/collections) - type-safe generic Java versions of Clojure's immutable (HAMT = 'Hash Array Mapped Trie') collections - arguably the best immutable collections on the JVM.  Plus an RRB Tree!\n* **Functional transformations** [api](https://javadoc.io/doc/org.organicdesign/Paguro/latest/org/organicdesign/fp/xform/package-summary.html) / [src](src/main/java/org/organicdesign/fp/xform/Transformable.java) are like a type-safe version of Clojure's Transducers, or a simplified immutable alternative to Java 8 Streams, wrapping checked exceptions and avoiding primitives (you can still use Java 8 streams if you want to).\n* **Brief collection constructors** [api](https://javadoc.io/doc/org.organicdesign/Paguro/latest/org/organicdesign/fp/StaticImports.html) / [src](src/main/java/org/organicdesign/fp/StaticImports.java) are like a tiny, type-safe data definition language (a little like JSON for Java):\n  * `vec(\"one\", \"two\", \"three\")` - an immutable vector/list of three strings\n  * `set(3, 5, 7)` - an immutable set of three integers\n  * `tup(\"Alice\", 11, 3.14)` - an immutable 3-field tuple or record\n  * `map(tup(1, \"single\"), tup(2, \"double\"), tup(3, \"triple\"))` - an immutable map that uses integers to look up appropriate strings.\n* **Extensible, immutable tuples** [api](https://javadoc.io/doc/org.organicdesign/Paguro/latest/org/organicdesign/fp/tuple/package-summary.html) / [src](src/main/java/org/organicdesign/fp/tuple) - use them for rapid, yet type-safe prototyping, then later extend them to make your own lightweight, immutable, serializable Java classes with correct `equals()`, `hashCode()`, and `toString()` implementations.\n* **Lazy initialization** [api](https://javadoc.io/doc/org.organicdesign/Paguro/latest/org/organicdesign/fp/function/LazyRef.html) / [src](src/main/java/org/organicdesign/fp/function/LazyRef.java) - LazyRef thread-safely performs initialization and frees initialization resources on first use.  Subsequent uses get the now-constant initialized value.  Use this instead of static initializers to avoid initialization loops.  Cache results of expensive operations for reuse.\n* **Union types** [api](https://javadoc.io/doc/org.organicdesign/Paguro/latest/org/organicdesign/fp/oneOf/package-summary.html) / [test](src/test/java/org/organicdesign/fp/oneOf/OneOf2Test.java) - Not as nice as being built into the language, but they extend type safety outside the object hierarchy.\n* **Memoization** [api](https://javadoc.io/doc/org.organicdesign/Paguro/latest/org/organicdesign/fp/function/Fn3.html) / [src](src/main/java/org/organicdesign/fp/function/Fn3.java) - Turns function calls into hashtable lookups to speed up slow functions over a limited range of inputs.\n* **Tiny** with no dependencies - The entire project fits in a ~270K jar file.\n\n# Examples\n\n[Usage examples](src/test/java/org/organicdesign/fp/UsageExampleTest.java) are implemented as unit tests to ensure that they remain correct and current.\n\n# What's the Most-Practical/Most-Used Part?\n- The stuff in StaticImports:\n  - `vec()`\n  - `map(tup(x, y), tup(a, b))`\n  - `xform()` and `xformArray()`\n - The functional interfaces: `Fn0`, `Fn1`, `Fn2`, `Fn3` because they wrap checked exceptions.\n - Because Java doesn't have sealed classes, I often write a lot of match() methods like those on the oneOf classes.  I probably copy the match() methods as often as I use most of the OneOf# classes.  It's a great way to say, \"Make sure you code for each of these cases every time you use this kind of thing.\"\n - `LazyRef`\n - `Tuple2` implements `Map.Entry\u003cK,V\u003e` which means I use the Map.Entry interface a lot more than I would otherwise (compare with `Pair\u003cA,B\u003e` in Kotlin).  Paguro lets you convert to and from maps easily, so this interface becomes super handy.  `Iterable\u003cMap.Entry\u003cK,V\u003e\u003e` becomes a pretty common input type.\n\n# Getting Started\n\n* [Class/Interface Hierarchy](inheritanceHierarchy.pdf) (PDF)\n* [API Docs](https://javadoc.io/doc/org.organicdesign/Paguro/latest/index.html)\n* Get started now by following the [Usage Tips](https://github.com/GlenKPeterson/Paguro/wiki/Usage-Tips)\n* [Comparison with Traditional Java and Java 8 Streams](src/test/java/org/organicdesign/fp/TradJavaStreamComparisonTest.java)\n\n# Classic\nYou are on the Paguro Classic, or main branch of this project.\nIf you work with pure Java, or a mix of Java and Kotlin files, this is your branch.\nI'm not sure the pure-Kotlin branch will ever be released.  Plain Java with `@NotNull` annotations gets you most of the way there, with almost no dependencies.\n\n# News\n## RrbTree.join() seems to work now\nRrbTree is still a new class, but as of 3.7.2, there are no known bugs.  Fingers crossed!\n\nCheck the [Change Log](CHANGE_LOG.md) for details of recent changes.\n\n# FAQ\n\n### Q: Why are you doing this?\n\nIt started with a Software Engineering Stack Exchange question: [Why doesn't Java provide immutable collections?](https://softwareengineering.stackexchange.com/questions/221762/why-doesnt-java-8-include-immutable-collections)\n\n### Q: How does this compare to PCollections?\n\n[Paguro is based on Clojure, is faster, and has additional features](https://github.com/GlenKPeterson/Paguro/wiki/UncleJim-vs.-PCollections)\n\n### Q: Do these Transforms create intermediate collections between each operation (like the Scala collections)?\n\n[No](https://github.com/GlenKPeterson/Paguro/wiki/How-do-%22Xforms%22---Transformations-work%3F)\n\n### Q: How does this compare to Streams and lambda expressions in JDK8?\n\n[Comparison](https://github.com/GlenKPeterson/Paguro/wiki/Comparison-with-Streams-and-Lambdas-in-JDK8)\n\n### Q: Why Java instead of another/better JVM language?\n\n[Why Java?](https://github.com/GlenKPeterson/Paguro/wiki/Why-is-Paguro-written-in-Java%3F)\nThat said, this could become a Kotlin-based project.\n\n# Licenses\nJava\u0026trade; is a registered trademark of the Oracle Corporation in the US and other countries.\nPaguro is not part of Java.\nOracle is in no way affiliated with the Paguro project.\n\nPaguro is not part of Clojure.\nRich Hickey and the Clojure team are in no way affiliated with the Paguro project, though it borrows heavily from their thoughts and is partly a derivative work of their open-source code.\n\nThe Clojure collections are licensed under the Eclipse Public License.\nVersions of them have been included in this project and modified to add type safety and implement different interfaces.\nThese files are still derivative works under the EPL.\n\nUnless otherwise stated, the rest of this work may be licensed under EITHER the Eclipse 1.0 or the Apache 2.0.\nYou get to choose!\nNew contributions should be made under both licenses whenever practical.\nI believe Apache is more popular, clearer, and has been better tested in courts of law.\n\nHermit Crab Photo by [Rushen](https://www.flickr.com/photos/rushen/12171498934/in/photostream/)\n\n# Contributing\n\nQuestions?  Ideas?  Feedback?  Use the [Google Group Email List](https://groups.google.com/d/forum/paguro).\nClear bugs or simple pull requests can be made on Github without discussing them first on the email list.\n\nIf you submit a patch, please:\n - Keep the changes minimal (don't let your IDE reformat whole files).\n - Try to match the code style as best you can.\n - Clearly document your changes.\n - Update the unit tests to clearly and simply prove that your code works.\n - It's a good idea to discuss proposed changes on the email list before you spend time coding.\n\n### Build from Source\n\nThe [pre-built jar file](https://search.maven.org/search?q=g:%22org.organicdesign%22%20AND%20a:%22Paguro%22) is the easiest way to use Paguro.\nUsers typically only build Paguro from source to make a contribution, or to experiment with the source code.\n\n#### Prerequisites\nPaguro is usually built on Ubuntu 18.04 and later with `openjdk-11`, `git`, and `maven` installed from the official repositories.\nBeing Java it should theoretically build with JDK 11+ on any system.\n\n##### Environment Variables\nDepending on how you installed Java and Maven, you may need to set some of the following in your `~/.profile` file and reboot (or source that file like `. ~/.profile` from the command line you will use for the build).\nOr do whatever Windows does.\nIf your tools are installed in different directories, you will have to fix the following:\n```bash\nexport JDK_HOME=/usr/lib/jvm/java-11-openjdk-amd64\nexport JAVA_HOME=$JDK_HOME/jre\nexport M2_HOME=$TOOLS/apache-maven-3.3.9/\nexport M2=\"$M2_HOME\"bin\nexport PATH=$PATH:$M2\n```\n\n##### Build\n```bash\n# Start in an appropriate directory\n\n# You need TestUtils for Paguro's equality testing.\n# The first time you build, get a local copy of that and Paguro\ngit clone https://github.com/GlenKPeterson/Paguro.git\n\n# Build Paguro:\ncd Paguro\ngit pull\nmvn clean install\n```\n\n# More\nAdditional information is in: [README2.md](README2.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglenkpeterson%2Fpaguro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fglenkpeterson%2Fpaguro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglenkpeterson%2Fpaguro/lists"}