{"id":13679394,"url":"https://github.com/yegor256/cactoos","last_synced_at":"2025-05-14T01:05:51.943Z","repository":{"id":21298587,"uuid":"92192594","full_name":"yegor256/cactoos","owner":"yegor256","description":"Object-Oriented Java primitives, as an alternative to Google Guava and Apache Commons","archived":false,"fork":false,"pushed_at":"2025-03-25T15:53:18.000Z","size":6216,"stargazers_count":749,"open_issues_count":78,"forks_count":173,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-04-03T06:48:38.737Z","etag":null,"topics":["java","java-library","oop","oop-library","oop-principles"],"latest_commit_sha":null,"homepage":"https://www.cactoos.org","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yegor256.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2017-05-23T16:00:02.000Z","updated_at":"2025-04-02T19:00:48.000Z","dependencies_parsed_at":"2023-10-01T19:45:53.704Z","dependency_job_id":"a7132c89-dae9-4cbc-bfe7-af96ad745477","html_url":"https://github.com/yegor256/cactoos","commit_stats":{"total_commits":2349,"total_committers":112,"mean_commits":"20.973214285714285","dds":0.8288633461047255,"last_synced_commit":"1c6a3bc0a09e5c4cc04c1c6fa32860503d6663f6"},"previous_names":[],"tags_count":92,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Fcactoos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Fcactoos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Fcactoos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Fcactoos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yegor256","download_url":"https://codeload.github.com/yegor256/cactoos/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248208690,"owners_count":21065205,"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":["java","java-library","oop","oop-library","oop-principles"],"created_at":"2024-08-02T13:01:05.093Z","updated_at":"2025-05-14T01:05:51.932Z","avatar_url":"https://github.com/yegor256.png","language":"Java","funding_links":[],"categories":["Projects","Java","工具库","项目"],"sub_categories":["Utility","实用程序"],"readme":"\u003cimg alt=\"logo\" src=\"https://www.objectionary.com/cactus.svg\" height=\"100px\" /\u003e\n\n[![EO principles respected here](https://www.elegantobjects.org/badge.svg)](https://www.elegantobjects.org)\n[![DevOps By Rultor.com](https://www.rultor.com/b/yegor256/cactoos)](https://www.rultor.com/p/yegor256/cactoos)\n[![We recommend IntelliJ IDEA](https://www.elegantobjects.org/intellij-idea.svg)](https://www.jetbrains.com/idea/)\n\n[![mvn](https://github.com/yegor256/cactoos/actions/workflows/mvn.yml/badge.svg)](https://github.com/yegor256/cactoos/actions/workflows/mvn.yml)\n[![Javadoc](https://www.javadoc.io/badge/org.cactoos/cactoos.svg)](https://www.javadoc.io/doc/org.cactoos/cactoos)\n[![PDD status](https://www.0pdd.com/svg?name=yegor256/cactoos)](https://www.0pdd.com/p?name=yegor256/cactoos)\n[![Maven Central](https://img.shields.io/maven-central/v/org.cactoos/cactoos.svg)](https://maven-badges.herokuapp.com/maven-central/org.cactoos/cactoos)\n[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/yegor256/cactoos/blob/master/LICENSE.txt)\n[![Test Coverage](https://img.shields.io/codecov/c/github/yegor256/cactoos.svg)](https://codecov.io/github/yegor256/cactoos?branch=master)\n[![SonarQube](https://img.shields.io/badge/sonar-ok-green.svg)](https://sonarcloud.io/dashboard?id=org.cactoos%3Acactoos)\n[![Hits-of-Code](https://hitsofcode.com/github/yegor256/cactoos)](https://hitsofcode.com/view/github/yegor256/cactoos)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/dc71110fe0ac43b8a535eec8b8fec389)](https://www.codacy.com/gh/yegor256/cactoos/dashboard)\n\nProject architect: [@victornoel](https://github.com/victornoel)\n\n**ATTENTION**: We're still in a very early alpha version, the API\nmay and _will_ change frequently. Please use it at your own risk\nuntil we release version 1.0. You can view our progress towards\nthis release [here](https://github.com/yegor256/cactoos/milestone/1).\n\nCactoos is a collection of object-oriented Java primitives.\n\n**Motivation**.\nWe are not happy with\n[JDK](https://en.wikipedia.org/wiki/Java_Development_Kit),\n[Guava](https://github.com/google/guava), and\n[Apache Commons](https://commons.apache.org/) because\nthey are procedural and not object-oriented. They do their job,\nbut mostly through static methods. Cactoos is suggesting\nto do almost exactly the same, but through objects.\n\n**Principles**.\nThese are the [design principles](https://www.elegantobjects.org#principles) behind Cactoos.\n\n**How to use**.\nThe library has no dependencies. All you need is this\n(get the latest version [here](https://github.com/yegor256/cactoos/releases)):\n\nMaven:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.cactoos\u003c/groupId\u003e\n  \u003cartifactId\u003ecactoos\u003c/artifactId\u003e\n  \u003cversion\u003e0.57.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGradle:\n\n```groovy\ndependencies {\n  compile 'org.cactoos:cactoos:0.57.0'\n}\n```\n\nJava version required: 1.8+.\n\nStackOverflow tag is [cactoos](https://stackoverflow.com/questions/tagged/cactoos).\n\n## Input/Output\n\nMore about it here:\n[Object-Oriented Declarative Input/Output in Cactoos](http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html).\n\nTo read a text file in UTF-8:\n\n```java\nString text = new TextOf(\n  new File(\"/code/a.txt\")\n).asString();\n```\n\nTo write a text into a file:\n\n```java\nnew LengthOf(\n  new TeeInput(\n    \"Hello, world!\",\n    new File(\"/code/a.txt\")\n  )\n).value();\n```\n\nTo read a binary file from classpath:\n\n```java\nbyte[] data = new BytesOf(\n  new ResourceOf(\"foo/img.jpg\")\n).asBytes();\n```\n\n## Text/Strings\n\nTo format a text:\n\n```java\nString text = new FormattedText(\n  \"How are you, %s?\",\n  name\n).asString();\n```\n\nTo manipulate text:\n\n```java\n// To lower case\nnew Lowered(\n  new TextOf(\"Hello\")\n);\n// To upper case\nnew Upper(\n  new TextOf(\"Hello\")\n);\n```\n\n## Iterables/Collections/Lists/Sets\n\nMore about it here: [Lazy Loading and Caching via Sticky Cactoos Primitives](http://www.yegor256.com/2017/10/17/lazy-loading-caching-sticky-cactoos.html).\n\nTo filter a collection:\n\n```java\nCollection\u003cString\u003e filtered = new ListOf\u003c\u003e(\n  new Filtered\u003c\u003e(\n    s -\u003e s.length() \u003e 4,\n    new IterableOf\u003c\u003e(\"hello\", \"world\", \"dude\")\n  )\n);\n```\n\nTo flatten one iterable:\n\n```java\nnew Joined\u003c\u003e(\n  new Mapped\u003cIterableOf\u003c\u003e\u003e(\n    iter -\u003e new IterableOf\u003c\u003e(\n      new ListOf\u003c\u003e(iter).toArray(new Integer[]{})\n    ),\n    new IterableOf\u003c\u003e(1, 2, 3, 4, 5, 6)\n  )\n);    // Iterable\u003cInteger\u003e\n```\n\nTo flatten and join several iterables:\n\n```java\nnew Joined\u003c\u003e(\n  new Mapped\u003cIterableOf\u003c\u003e\u003e(\n    iter -\u003e new IterableOf\u003c\u003e(\n      new Joined\u003c\u003e(iter)\n    ),\n    new Joined\u003c\u003e(\n      new IterableOf\u003c\u003e(new IterableOf\u003c\u003e(1, 2, 3)),\n      new IterableOf\u003c\u003e(new IterableOf\u003c\u003e(4, 5, 6))\n    )\n  )\n);    // Iterable\u003cInteger\u003e\n```\n\nTo iterate a collection:\n\n```java\nnew And(\n  new Mapped\u003c\u003e(\n    new FuncOf\u003c\u003e(\n      input -\u003e {\n        System.out.printf(\"Item: %s\\n\", input);\n      },\n      new True()\n    ),\n    new IterableOf\u003c\u003e(\"how\", \"are\", \"you\", \"?\")\n  )\n).value();\n```\n\nOr even more compact:\n\n```java\nnew ForEach\u003c\u003e(\n  input -\u003e System.out.printf(\n    \"Item: %s\\n\", input\n  )\n).exec(new IterableOf\u003c\u003e(\"how\", \"are\", \"you\", \"?\"));\n```\n\nTo sort a list of words in the file:\n\n```java\nList\u003cText\u003e sorted = new ListOf\u003c\u003e(\n  new Sorted\u003c\u003e(\n    new Mapped\u003c\u003e(\n      text -\u003e new ComparableText(text),\n      new Split(\n        new TextOf(\n          new File(\"/tmp/names.txt\")\n        ),\n        new TextOf(\"\\\\s+\")\n      )\n    )\n  )\n);\n```\n\nTo count elements in an iterable:\n\n```java\nint total = new LengthOf(\n  new IterableOf\u003c\u003e(\"how\", \"are\", \"you\")\n).value().intValue();\n```\n\nTo create a set of elements by providing variable arguments:\n\n```java\nfinal Set\u003cString\u003e unique = new SetOf\u003c\u003e(\n  \"one\",\n  \"two\",\n  \"one\",\n  \"three\"\n);\n```\n\nTo create a set of elements from an existing iterable:\n```java\nfinal Set\u003cString\u003e words = new SetOf\u003c\u003e(\n  new IterableOf\u003c\u003e(\"abc\", \"bcd\", \"abc\", \"ccc\")\n);\n```\n\nTo create a sorted iterable with unique elements from an existing iterable:\n```java\nfinal Iterable\u003cString\u003e sorted = new Sorted\u003c\u003e(\n  new SetOf\u003c\u003e(\n    new IterableOf\u003c\u003e(\"abc\", \"bcd\", \"abc\", \"ccc\")\n  )\n);\n```\n\nTo create a sorted set from existing vararg elements using a comparator:\n```java\nfinal Set\u003cString\u003e sorted = new org.cactoos.set.Sorted\u003c\u003e(\n  (first, second) -\u003e first.compareTo(second),\n  \"abc\", \"bcd\", \"abc\", \"ccc\", \"acd\"\n);\n```\n\nTo create a sorted set from an existing iterable using a comparator:\n```java\nfinal Set\u003cString\u003e sorted = new org.cactoos.set.Sorted\u003c\u003e(\n  (first, second) -\u003e first.compareTo(second),\n  new IterableOf\u003c\u003e(\"abc\", \"bcd\", \"abc\", \"ccc\", \"acd\")\n);\n```\n\n## Funcs and Procs\n\nThis is a traditional `foreach` loop:\n\n```java\nfor (String name : names) {\n  System.out.printf(\"Hello, %s!\\n\", name);\n}\n```\n\nThis is its object-oriented alternative (no streams!):\n\n```java\nnew And(\n  n -\u003e {\n    System.out.printf(\"Hello, %s!\\n\", n);\n    return new True().value();\n  },\n  names\n).value();\n```\n\nThis is an endless `while/do` loop:\n\n```java\nwhile (!ready) {\n  System.out.println(\"Still waiting...\");\n}\n```\n\nHere is its object-oriented alternative:\n\n```java\nnew And(\n  ready -\u003e {\n    System.out.println(\"Still waiting...\");\n    return !ready;\n  },\n  new Endless\u003c\u003e(booleanParameter)\n).value();\n```\n\n## Dates and Times\nFrom our `org.cactoos.time` package.\n\nOur classes are divided in two groups: those that parse strings into date/time objects, and those that format those objects into strings.\n\nFor example, this is the traditional way of parsing a string into an [OffsetDateTime](https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html):\n\n```java\nfinal OffsetDateTime date = OffsetDateTime.parse(\"2007-12-03T10:15:30+01:00\");\n```\n\nHere is its object-oriented alternative (no static method calls!) using `OffsetDateTimeOf`, which is a `Scalar`:\n\n```java\nfinal OffsetDateTime date = new OffsetDateTimeOf(\"2007-12-03T10:15:30+01:00\").value();\n```\n\nTo format an `OffsetDateTime` into a `Text`:\n\n```java\nfinal OffsetDateTime date = ...;\nfinal String text = new TextOfDateTime(date).asString();\n```\n\n## Our objects vs. their static methods\n\nCactoos | Guava | Apache Commons | JDK 8\n------ | ------ | ------ | ------\n`And` | `Iterables.all()` | - | -\n`Filtered` | `Iterables.filter()` | ? | -\n`FormattedText` | - | - | `String.format()`\n`IsBlank` | - | `StringUtils.isBlank()`| -\n`Joined` | - | - | `String.join()`\n`LengthOf` | - | - | `String#length()`\n`Lowered` | - | - | `String#toLowerCase()`\n`Normalized` | - | `StringUtils.normalize()` | -\n`Or` | `Iterables.any()` | - | -\n`Repeated` | - | `StringUtils.repeat()` | -\n`Replaced` | - | - | `String#replace()`\n`Reversed` | - | - | `StringBuilder#reverse()`\n`Rotated` | - | `StringUtils.rotate()`| -\n`Split` | - | - | `String#split()`\n`StickyList` | `Lists.newArrayList()` | ? | `Arrays.asList()`\n`Sub` | - | - | `String#substring()`\n`SwappedCase` | - | `StringUtils.swapCase()` | -\n`TextOf` | ? | `IOUtils.toString()` | -\n`TrimmedLeft` | - | `StringUtils.stripStart()` | -\n`TrimmedRight` | - | `StringUtils.stripEnd()` | -\n`Trimmed` | - | `StringUtils.stripAll()` | `String#trim()`\n`Upper` | - | - | `String#toUpperCase()`\n\n## Questions\n\nAsk your questions related to cactoos library on [Stackoverflow](https://stackoverflow.com/questions/ask) with [cactoos](https://stackoverflow.com/tags/cactoos/info) tag.\n\n## How to contribute?\n\nJust fork the repo and send us a pull request.\n\nMake sure your branch builds without any warnings/issues:\n```bash\nmvn clean verify -Pqulice\n```\n\nTo run a build similar to the CI with Docker only, use:\n```bash\ndocker run \\\n\t--tty \\\n\t--interactive \\\n\t--workdir=/main \\\n\t--volume=${PWD}:/main \\\n\t--volume=cactoos-mvn-cache:/root/.m2 \\\n\t--rm \\\n\tmaven:3-jdk-8 \\\n\tbash -c \"mvn clean install site -Pqulice -Psite --errors; chown -R $(id -u):$(id -g) target/\"\n```\n\nTo remove the cache used by Docker-based build:\n```bash\ndocker volume rm cactoos-mvn-cache\n```\n\nNote: [Checkstyle](https://en.wikipedia.org/wiki/Checkstyle) is used as a static code analysis tool with\n[checks list](http://checkstyle.sourceforge.net/checks.html) in GitHub precommits.\n\n## Contributors\n\n  - [@yegor256](https://github.com/yegor256) as Yegor Bugayenko ([Blog](http://www.yegor256.com))\n  - [@g4s8](https://github.com/g4s8) as Kirill Che. (g4s8.public@gmail.com)\n  - [@fabriciofx](https://github.com/fabriciofx) as Fabrício Cabral\n  - [@englishman](https://github.com/englishman) as Andriy Kryvtsun\n  - [@VsSekorin](https://github.com/VsSekorin) as Vseslav Sekorin\n  - [@DronMDF](https://github.com/DronMDF) as Andrey Valyaev\n  - [@dusan-rychnovsky](https://github.com/dusan-rychnovsky) as Dušan Rychnovský ([Blog](http://blog.dusanrychnovsky.cz/))\n  - [@timmeey](https://github.com/timmeey) as Tim Hinkes ([Blog](https://blog.timmeey.de))\n  - [@alex-semenyuk](https://github.com/alex-semenyuk) as Alexey Semenyuk\n  - [@smallcreep](https://github.com/smallcreep) as Ilia Rogozhin\n  - [@memoyil](https://github.com/memoyil) as Mehmet Yildirim\n  - [@llorllale](https://github.com/llorllale) as George Aristy\n  - [@driver733](https://github.com/driver733) as Mikhail Yakushin\n  - [@izrik](https://github.com/izrik) as Richard Sartor\n  - [@Vatavuk](https://github.com/Vatavuk) as Vedran Grgo Vatavuk\n  - [@dgroup](https://github.com/dgroup) as Yurii Dubinka\n  - [@iakunin](https://github.com/iakunin) as Maksim Iakunin\n  - [@fanifieiev](https://github.com/fanifieiev) as Fevzi Anifieiev\n  - [@victornoel](https://github.com/victornoel) as Victor Noël\n  - [@paulodamaso](https://github.com/paulodamaso) as Paulo Lobo\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyegor256%2Fcactoos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyegor256%2Fcactoos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyegor256%2Fcactoos/lists"}