diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d8000877..c1cc8abb 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -51,6 +51,39 @@ Common pitfalls and fixes Linting & style - The root does not expose an obvious global formatting tool (no Spotless or root Checkstyle detected). Use the existing code style. Run `./gradlew check` to execute configured verification tasks. +Testing conventions +- Use AssertJ for assertions (import `org.assertj.core.api.Assertions`), not JUnit's `Assertions`. +- Test class naming: `Test.java` in the same package under `src/test/java`. +- Test class visibility: use package-private (no `public` modifier) for test classes. +- Test method naming: `should` pattern (e.g., `shouldReturnEmptyArrayForNullInput`). +- Use given/when/then comments with trailing colons to structure test methods (e.g., `// given:`, `// when:`, `// then:`, `// when/then:`). +- For cleanup steps, use `// cleanup:` comment section at the end of the test method. +- Prefer project collections (e.g., `MutableArray`) over JDK collections (e.g., `ArrayList`) in tests when appropriate. +- Use proper imports instead of fully qualified class names in test code. +- When adding new public methods, ensure corresponding unit tests are added. +- Use JUnit's `@TempDir Path tempDir` parameter injection for tests that need temporary directories instead of manually creating temp directories with `Files.createTempDirectory()`. +- For resources created outside `@TempDir` (e.g., `Files.createTempFile()`), add explicit cleanup in the `// cleanup:` section. +- For `assertThat()` calls: break method chains onto new lines with indentation when the assertion has arguments or multiple chained methods (e.g., `assertThat(result)\n .isEqualTo("expected")`). Short simple assertions can stay on one line. +- For fluent builder/method chains: break onto new lines with indentation (e.g., `tempDir\n .resolve("level1")\n .resolve("level2")`). + +Javadoc conventions +- All public classes, interfaces, and methods should have javadoc. +- Javadoc must include `@since` tag with version (e.g., `@since 10.0.0`). +- Use short, active-voice descriptions (e.g., "Returns an array" not "Return an array"). +- Do not use trailing periods in `@param` and `@return` descriptions (e.g., `@param value the value` not `@param value the value.`). +- Include `@param` and `@return` tags for non-trivial methods. +- Omit javadoc for simple getters/setters (e.g., `getArch()`, `setArch(String)`); they are self-explanatory. +- Omit obvious field comments that just repeat the field name (e.g., `/** The name. */ private String name;`). +- Omit obvious constant comments (e.g., `/** The constant FOO. */ public static final String FOO = "foo";`). +- Type parameter descriptions should use consistent format: "the type of..." (e.g., `@param the type of elements` not `@param the element type`). +- Do not generate javadoc for implementation classes (only interfaces and public API classes). +- For `@see` tags, avoid duplicate references (e.g., use `@see Math#sin(double)` not `@see Math#sin(double) Math#sin(double)`). +- For functional interfaces: + - Consumer descriptions must include "and returns no result" (e.g., "Represents an operation that accepts an int and an object argument, and returns no result."). + - Use type-specific @param descriptions (e.g., "the int argument", "the object argument") instead of generic "the first argument". + - Function @return should use "the function result" for consistency. + - Predicate @return should use "true if the arguments match the predicate". + Project layout & where to change things - Root-level important files: - `build.gradle` — root build settings, wrapper config. diff --git a/.github/skills/generate-javadoc.md b/.github/skills/generate-javadoc.md index 31d8dd93..ebd02027 100644 --- a/.github/skills/generate-javadoc.md +++ b/.github/skills/generate-javadoc.md @@ -8,6 +8,8 @@ When the user asks to: - Generate javadocs for a module - Add documentation to public APIs - Document interfaces/classes with `@since` tags +- Review and fix existing javadocs +- Clean up javadoc formatting ## Requirements @@ -16,23 +18,42 @@ When the user asks to: 2. **Skip implementation classes** - files in `impl/` packages are NOT documented 3. **Skip test classes** - files in `src/test/` are NOT documented +### What to Omit +1. **Simple getters/setters** - methods like `getArch()`, `setArch(String)` are self-explanatory +2. **Obvious field comments** - avoid comments that just repeat the field name (e.g., `/** The name. */ private String name;`) +3. **Obvious constructor javadocs** - avoid comments like "Instantiates a new Foo" +4. **Obvious constant comments** - avoid comments like "The constant FOO" for `public static final String FOO` + +### Formatting Rules +1. **Active voice** - use "Returns" not "Return", "Creates" not "Create" +2. **No trailing periods** - in `@param` and `@return` descriptions (e.g., `@param value the value` not `@param value the value.`) +3. **No duplicate @see references** - use `@see Math#sin(double)` not `@see Math#sin(double) Math#sin(double)` +4. **Lowercase @param/@return descriptions** - start with lowercase (e.g., `@param value the value` not `@param value The value`) +5. **Consistent type parameter format** - use "the type of..." pattern (e.g., `@param the type of elements` not `@param the element type`) +6. **Descriptive @param names** - for functional interfaces, use type-specific descriptions (e.g., "the int argument", "the object argument") instead of generic "the first argument" + +### Functional Interface Conventions +1. **Consumer descriptions** - always include "and returns no result" (e.g., "Represents an operation that accepts an int and an object argument, and returns no result.") +2. **Function @return** - use "the function result" for consistency +3. **Predicate @return** - use "true if the arguments match the predicate" or "true if the arguments match the predicate, false otherwise" +4. **Supplier @return** - describe what is supplied (e.g., "the char value" not just "a result") + ### Javadoc Standards Each documented element must include: 1. **Class/Interface level:** - - Short description of purpose - - `@param` for type parameters (if generic) - - `@author JavaSaBr` + - Short description of purpose (active voice) + - `@param` for type parameters with meaningful descriptions (if generic) - `@since 10.0.0` 2. **Method level:** - - Short description for ALL methods + - Short description for non-trivial methods - `@param` and `@return` only for **non-trivial** methods - `@since 10.0.0` - `@throws` only when explicitly thrown 3. **Constants/Fields:** - - Short description + - Short description (only if not obvious from the name) - `@since 10.0.0` ### Example Format @@ -42,7 +63,6 @@ Each documented element must include: * An immutable array interface that provides type-safe, indexed access to elements. * * @param the type of elements in this array - * @author JavaSaBr * @since 10.0.0 */ public interface Array extends Iterable { @@ -79,6 +99,37 @@ public interface Array extends Iterable { } ``` +### Functional Interface Example + +```java +/** + * Represents an operation that accepts an int and an object argument, and returns no result. + * + * @param the type of the object argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface IntObjConsumer { + + /** + * Performs this operation on the given arguments. + * + * @param arg1 the int argument + * @param arg2 the object argument + * @since 10.0.0 + */ + void accept(int arg1, B arg2); +} +``` + +### Common Fixes When Reviewing Existing Javadocs +- Change "Return the" to "Returns the" +- Change "Compare the" to "Compares the" +- Remove trailing periods from `@param` and `@return` lines +- Remove obvious/redundant javadocs (getters, setters, constants) +- Remove duplicate `@see` references +- Add missing `@since` tags + ## Execution Steps 1. **Analyze module structure:** @@ -94,7 +145,7 @@ public interface Array extends Iterable { 3. **Read each file** to understand existing documentation state 4. **Add Javadocs** using `replace_string_in_file` tool: - - Add class-level Javadoc with description, `@author`, `@since` + - Add class-level Javadoc with description and `@since` - Add method-level Javadocs with description and `@since` - Add `@param`/`@return` only for non-trivial methods diff --git a/README.md b/README.md index 50a1e115..4f0133c4 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ repositories { } ext { - rlibVersion = "10.0.alpha12" + rlibVersion = "10.0.alpha13" } dependencies { diff --git a/build.gradle b/build.gradle index b05bd7a9..93de4b81 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -rootProject.version = "10.0.alpha12" +rootProject.version = "10.0.alpha13" group = 'javasabr.rlib' allprojects { diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/ArrayIterationFunctions.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/ArrayIterationFunctions.java index fdd7943a..87dc8f5b 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/array/ArrayIterationFunctions.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/ArrayIterationFunctions.java @@ -2,8 +2,8 @@ import java.util.function.BiConsumer; import java.util.function.BiPredicate; +import javasabr.rlib.functions.BiObjLongConsumer; import javasabr.rlib.functions.ObjIntPredicate; -import javasabr.rlib.functions.ObjObjLongConsumer; import javasabr.rlib.functions.TriConsumer; import org.jspecify.annotations.Nullable; @@ -80,7 +80,7 @@ public interface ArrayIterationFunctions { * @return this for method chaining * @since 10.0.0 */ - ArrayIterationFunctions forEach(A arg1, long arg2, ObjObjLongConsumer consumer); + ArrayIterationFunctions forEach(A arg1, long arg2, BiObjLongConsumer consumer); /** * Returns whether any element matches the filter predicate. diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultArrayIterationFunctions.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultArrayIterationFunctions.java index d3d5c54a..6adf1c19 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultArrayIterationFunctions.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultArrayIterationFunctions.java @@ -5,8 +5,8 @@ import javasabr.rlib.collections.array.ArrayIterationFunctions; import javasabr.rlib.collections.array.ReversedArgsArrayIterationFunctions; import javasabr.rlib.collections.array.UnsafeArray; +import javasabr.rlib.functions.BiObjLongConsumer; import javasabr.rlib.functions.ObjIntPredicate; -import javasabr.rlib.functions.ObjObjLongConsumer; import javasabr.rlib.functions.TriConsumer; import org.jspecify.annotations.Nullable; @@ -64,7 +64,7 @@ public ArrayIterationFunctions forEach(F arg1, S arg2, TriConsumer ArrayIterationFunctions forEach(F arg1, long arg2, ObjObjLongConsumer consumer) { + public ArrayIterationFunctions forEach(F arg1, long arg2, BiObjLongConsumer consumer) { @Nullable E[] wrapped = array.wrapped(); int size = array.size(); for (int i = 0; i < size; i++) { diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableArray.java index 1b5baa8b..d0bf739a 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableArray.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableArray.java @@ -81,7 +81,7 @@ public ImmutableArray(Class type, E e1, E e2, E e3, E e4, E e5, E e6) @SafeVarargs public ImmutableArray(Class type, E... elements) { super(type); - if (ArrayUtils.getComponentType(elements) == type) { + if (ArrayUtils.resolveComponentType(elements) == type) { this.wrapped = elements; return; } diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/operation/LockableOperations.java b/rlib-collections/src/main/java/javasabr/rlib/collections/operation/LockableOperations.java index 1733bb1a..376db74f 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/operation/LockableOperations.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/operation/LockableOperations.java @@ -4,7 +4,7 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; -import javasabr.rlib.functions.BiObjToBooleanFunction; +import javasabr.rlib.functions.BiObjToBoolFunction; import javasabr.rlib.functions.ObjIntFunction; import javasabr.rlib.functions.TriConsumer; import javasabr.rlib.functions.TriFunction; @@ -73,7 +73,7 @@ public interface LockableOperations { * @return the boolean result * @since 10.0.0 */ - boolean getBooleanInReadLock(A arg1, BiObjToBooleanFunction function); + boolean getBooleanInReadLock(A arg1, BiObjToBoolFunction function); /** * Executes a consumer within a read lock with one argument. diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/operation/impl/DefaultLockableOperations.java b/rlib-collections/src/main/java/javasabr/rlib/collections/operation/impl/DefaultLockableOperations.java index 02098d71..8aa88407 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/operation/impl/DefaultLockableOperations.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/operation/impl/DefaultLockableOperations.java @@ -6,7 +6,7 @@ import java.util.function.Function; import javasabr.rlib.collections.operation.LockableOperations; import javasabr.rlib.collections.operation.LockableSource; -import javasabr.rlib.functions.BiObjToBooleanFunction; +import javasabr.rlib.functions.BiObjToBoolFunction; import javasabr.rlib.functions.ObjIntFunction; import javasabr.rlib.functions.TriConsumer; import javasabr.rlib.functions.TriFunction; @@ -55,7 +55,7 @@ public R getInReadLock(A arg1, B arg2, TriFunction functio } @Override - public boolean getBooleanInReadLock(A arg1, BiObjToBooleanFunction function) { + public boolean getBooleanInReadLock(A arg1, BiObjToBoolFunction function) { long stamp = source.readLock(); try { return function.apply(source, arg1); diff --git a/rlib-common/build.gradle b/rlib-common/build.gradle index a70affdd..1499fe59 100644 --- a/rlib-common/build.gradle +++ b/rlib-common/build.gradle @@ -5,4 +5,5 @@ plugins { dependencies { api projects.rlibLoggerApi + api projects.rlibFunctions } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/Copyable.java b/rlib-common/src/main/java/javasabr/rlib/common/Copyable.java index 880af8e0..3ea8cfb1 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/Copyable.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/Copyable.java @@ -1,5 +1,17 @@ package javasabr.rlib.common; +/** + * Represents an object that can create a copy of itself. + * + * @param the type of the object to be copied + * @since 10.0.0 + */ public interface Copyable { + + /** + * Creates a copy of this object. + * + * @return a copy of this object + */ T copy(); } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/ThreadSafe.java b/rlib-common/src/main/java/javasabr/rlib/common/ThreadSafe.java index 7d60d159..a20c8925 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/ThreadSafe.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/ThreadSafe.java @@ -1,6 +1,11 @@ package javasabr.rlib.common; /** - * Interface to mark a class that it's a thread safe. + * Marker interface to indicate that a class is thread-safe. + *

+ * Classes implementing this interface guarantee that their instances can be safely + * accessed by multiple threads concurrently without external synchronization. + * + * @since 10.0.0 */ public interface ThreadSafe {} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/CharSupplier.java b/rlib-common/src/main/java/javasabr/rlib/common/function/CharSupplier.java deleted file mode 100644 index 5a9d03bb..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/CharSupplier.java +++ /dev/null @@ -1,28 +0,0 @@ -package javasabr.rlib.common.function; - -import java.util.function.Supplier; - -/** - * Represents a supplier of {@code char}-valued results. This is the {@code char}-producing primitive specialization of - * {@link Supplier}. - * - *

There is no requirement that a distinct result be returned each - * time the supplier is invoked. - * - *

This is a functional interface - * whose functional method is {@link #getAsChar()}. - * - * @author JavaSaBr - * @see Supplier - * @since 8.1.0 - */ -@FunctionalInterface -public interface CharSupplier { - - /** - * Gets a result. - * - * @return a result - */ - char getAsChar(); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/DoubleObjectConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/DoubleObjectConsumer.java deleted file mode 100644 index ed466073..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/DoubleObjectConsumer.java +++ /dev/null @@ -1,21 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * The function. - * - * @param the type parameter - * @author JavaSaBr - */ -@FunctionalInterface -public interface DoubleObjectConsumer { - - /** - * Accept. - * - * @param first the first - * @param second the second - */ - void accept(double first, @Nullable T second); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/FloatBiObjectConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/FloatBiObjectConsumer.java deleted file mode 100644 index 2f82b8e8..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/FloatBiObjectConsumer.java +++ /dev/null @@ -1,13 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.NullUnmarked; - -/** - * @author JavaSaBr - */ -@NullUnmarked -@FunctionalInterface -public interface FloatBiObjectConsumer { - - void accept(float first, S second, T third); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/FloatConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/FloatConsumer.java deleted file mode 100644 index 91731171..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/FloatConsumer.java +++ /dev/null @@ -1,17 +0,0 @@ -package javasabr.rlib.common.function; - -/** - * The function to consume float values. - * - * @author JavaSaBr - */ -@FunctionalInterface -public interface FloatConsumer { - - /** - * Consume the float value. - * - * @param value the value. - */ - void consume(float value); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/FunctionInt.java b/rlib-common/src/main/java/javasabr/rlib/common/function/FunctionInt.java deleted file mode 100644 index 6cdad4d0..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/FunctionInt.java +++ /dev/null @@ -1,21 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * The function. - * - * @param the type parameter - * @author JavaSaBr - */ -@FunctionalInterface -public interface FunctionInt { - - /** - * Apply int. - * - * @param first the first - * @return the int - */ - int apply(@Nullable T first); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/Functions.java b/rlib-common/src/main/java/javasabr/rlib/common/function/Functions.java deleted file mode 100644 index 374c09b1..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/Functions.java +++ /dev/null @@ -1,68 +0,0 @@ -package javasabr.rlib.common.function; - -import java.util.function.Predicate; -import java.util.function.Supplier; - -public class Functions { - - public static class Predicates { - - public static Predicate isTrue() { - - return bool -> bool; - } - - public static Predicate ifTrue(Runnable task) { - - return bool -> { - - if (bool) { - task.run(); - } - - return true; - }; - } - - public static Predicate throwIfTrue(Supplier factory) { - - return bool -> { - - if (bool) { - throw factory.get(); - } - - return true; - }; - } - - public static Predicate isFalse() { - - return bool -> !bool; - } - - public static Predicate ifFalse(Runnable task) { - - return bool -> { - - if (!bool) { - task.run(); - } - - return true; - }; - } - - public static Predicate throwIfFalse(Supplier factory) { - - return bool -> { - - if (!bool) { - throw factory.get(); - } - - return true; - }; - } - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/IntBiObjectConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/IntBiObjectConsumer.java deleted file mode 100644 index c376f780..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/IntBiObjectConsumer.java +++ /dev/null @@ -1,24 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.NullUnmarked; - -/** - * The function. - * - * @param the type parameter - * @param the type parameter - * @author JavaSaBr - */ -@NullUnmarked -@FunctionalInterface -public interface IntBiObjectConsumer { - - /** - * Accept. - * - * @param first the first - * @param second the second - * @param third the third - */ - void accept(int first, S second, T third); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/IntObjectPredicate.java b/rlib-common/src/main/java/javasabr/rlib/common/function/IntObjectPredicate.java deleted file mode 100644 index 49ab72a6..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/IntObjectPredicate.java +++ /dev/null @@ -1,22 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * The function. - * - * @param the type parameter - * @author JavaSaBr - */ -@FunctionalInterface -public interface IntObjectPredicate { - - /** - * Test boolean. - * - * @param first the first - * @param second the second - * @return the boolean - */ - boolean test(int first, @Nullable T second); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/LongBiObjectConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/LongBiObjectConsumer.java deleted file mode 100644 index 7fbff7c0..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/LongBiObjectConsumer.java +++ /dev/null @@ -1,24 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.NullUnmarked; - -/** - * The function. - * - * @param the type parameter - * @param the type parameter - * @author JavaSaBr - */ -@NullUnmarked -@FunctionalInterface -public interface LongBiObjectConsumer { - - /** - * Accept. - * - * @param first the first - * @param second the second - * @param third the third - */ - void accept(long first, S second, T third); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/LongObjectPredicate.java b/rlib-common/src/main/java/javasabr/rlib/common/function/LongObjectPredicate.java deleted file mode 100644 index 4e5b7bc6..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/LongObjectPredicate.java +++ /dev/null @@ -1,22 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * ФThe function. - * - * @param the type parameter - * @author JavaSaBr - */ -@FunctionalInterface -public interface LongObjectPredicate { - - /** - * Test boolean. - * - * @param first the first - * @param second the second - * @return the boolean - */ - boolean test(long first, @Nullable T second); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullBiConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullBiConsumer.java deleted file mode 100644 index 98777de7..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullBiConsumer.java +++ /dev/null @@ -1,10 +0,0 @@ -package javasabr.rlib.common.function; - -import java.util.function.BiConsumer; - -@FunctionalInterface -public interface NotNullBiConsumer extends BiConsumer { - - @Override - void accept(T first, U second); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullConsumer.java deleted file mode 100644 index 4e12ded8..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullConsumer.java +++ /dev/null @@ -1,10 +0,0 @@ -package javasabr.rlib.common.function; - -import java.util.function.Consumer; - -@FunctionalInterface -public interface NotNullConsumer extends Consumer { - - @Override - void accept(T object); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeBiConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeBiConsumer.java deleted file mode 100644 index 605ff62b..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeBiConsumer.java +++ /dev/null @@ -1,11 +0,0 @@ -package javasabr.rlib.common.function; - -/** - * @author JavaSaBr - */ -@FunctionalInterface -public interface NotNullSafeBiConsumer extends SafeBiConsumer { - - @Override - void accept(F first, S second) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeBiFunction.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeBiFunction.java deleted file mode 100644 index f355483b..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeBiFunction.java +++ /dev/null @@ -1,8 +0,0 @@ -package javasabr.rlib.common.function; - -@FunctionalInterface -public interface NotNullSafeBiFunction extends SafeBiFunction { - - @Override - R apply(F first, S second) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeConsumer.java deleted file mode 100644 index bbb7760b..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeConsumer.java +++ /dev/null @@ -1,11 +0,0 @@ -package javasabr.rlib.common.function; - -/** - * @author JavaSaBr - */ -@FunctionalInterface -public interface NotNullSafeConsumer extends SafeConsumer { - - @Override - void accept(T argument) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeFactory.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeFactory.java deleted file mode 100644 index c613fd45..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeFactory.java +++ /dev/null @@ -1,11 +0,0 @@ -package javasabr.rlib.common.function; - -/** - * @author JavaSaBr - */ -@FunctionalInterface -public interface NotNullSafeFactory extends SafeFactory { - - @Override - R get() throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeFunction.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeFunction.java deleted file mode 100644 index db4f2135..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeFunction.java +++ /dev/null @@ -1,8 +0,0 @@ -package javasabr.rlib.common.function; - -@FunctionalInterface -public interface NotNullSafeFunction extends SafeFunction { - - @Override - R apply(F first) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeSupplier.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeSupplier.java deleted file mode 100644 index 8e22851b..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeSupplier.java +++ /dev/null @@ -1,11 +0,0 @@ -package javasabr.rlib.common.function; - -/** - * @author JavaSaBr - */ -@FunctionalInterface -public interface NotNullSafeSupplier extends SafeSupplier { - - @Override - T get() throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeTriFunction.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeTriFunction.java deleted file mode 100644 index ef4b91e0..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NotNullSafeTriFunction.java +++ /dev/null @@ -1,8 +0,0 @@ -package javasabr.rlib.common.function; - -@FunctionalInterface -public interface NotNullSafeTriFunction extends SafeTriFunction { - - @Override - R apply(F first, S second, T third) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/NullableSupplier.java b/rlib-common/src/main/java/javasabr/rlib/common/function/NullableSupplier.java deleted file mode 100644 index 1749584f..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/NullableSupplier.java +++ /dev/null @@ -1,11 +0,0 @@ -package javasabr.rlib.common.function; - -import java.util.function.Supplier; -import org.jspecify.annotations.Nullable; - -@FunctionalInterface -public interface NullableSupplier extends Supplier { - - @Override - @Nullable T get(); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/ObjectIntFunction.java b/rlib-common/src/main/java/javasabr/rlib/common/function/ObjectIntFunction.java deleted file mode 100644 index 0fbd2093..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/ObjectIntFunction.java +++ /dev/null @@ -1,23 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * The function. - * - * @param the type parameter - * @param the type parameter - * @author JavaSaBr - */ -@FunctionalInterface -public interface ObjectIntFunction { - - /** - * Apply r. - * - * @param first the first - * @param second the second - * @return the r - */ - @Nullable R apply(@Nullable T first, int second); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/ObjectLongPredicate.java b/rlib-common/src/main/java/javasabr/rlib/common/function/ObjectLongPredicate.java deleted file mode 100644 index 58caee26..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/ObjectLongPredicate.java +++ /dev/null @@ -1,22 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * The function. - * - * @param the type parameter - * @author JavaSaBr - */ -@FunctionalInterface -public interface ObjectLongPredicate { - - /** - * Test boolean. - * - * @param first the first - * @param second the second - * @return the boolean - */ - boolean test(@Nullable T first, long second); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeBiConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/SafeBiConsumer.java deleted file mode 100644 index 823ed828..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeBiConsumer.java +++ /dev/null @@ -1,12 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * @author JavaSaBr - */ -@FunctionalInterface -public interface SafeBiConsumer { - - void accept(@Nullable F first, @Nullable S second) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeBiFunction.java b/rlib-common/src/main/java/javasabr/rlib/common/function/SafeBiFunction.java deleted file mode 100644 index 8f5e95a2..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeBiFunction.java +++ /dev/null @@ -1,9 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -@FunctionalInterface -public interface SafeBiFunction { - - @Nullable R apply(@Nullable F first, @Nullable S second) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/SafeConsumer.java deleted file mode 100644 index ea0ce44f..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeConsumer.java +++ /dev/null @@ -1,12 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * @author JavaSaBr - */ -@FunctionalInterface -public interface SafeConsumer { - - void accept(@Nullable T argument) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeFactory.java b/rlib-common/src/main/java/javasabr/rlib/common/function/SafeFactory.java deleted file mode 100644 index 0eb7a2df..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * @author JavaSaBr - */ -@FunctionalInterface -public interface SafeFactory { - - @Nullable R get() throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeFunction.java b/rlib-common/src/main/java/javasabr/rlib/common/function/SafeFunction.java deleted file mode 100644 index f7fb2a5d..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeFunction.java +++ /dev/null @@ -1,9 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -@FunctionalInterface -public interface SafeFunction { - - @Nullable R apply(@Nullable F first) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeRunnable.java b/rlib-common/src/main/java/javasabr/rlib/common/function/SafeRunnable.java deleted file mode 100644 index 20aafe97..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeRunnable.java +++ /dev/null @@ -1,17 +0,0 @@ -package javasabr.rlib.common.function; - -/** - * The function. - * - * @author JavaSaBr - */ -@FunctionalInterface -public interface SafeRunnable { - - /** - * Run. - * - * @throws Exception the exception - */ - void run() throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeSupplier.java b/rlib-common/src/main/java/javasabr/rlib/common/function/SafeSupplier.java deleted file mode 100644 index 57e9013b..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeSupplier.java +++ /dev/null @@ -1,12 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.Nullable; - -/** - * @author JavaSaBr - */ -@FunctionalInterface -public interface SafeSupplier { - - @Nullable T get() throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeTriFunction.java b/rlib-common/src/main/java/javasabr/rlib/common/function/SafeTriFunction.java deleted file mode 100644 index 409125be..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/SafeTriFunction.java +++ /dev/null @@ -1,10 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.NullUnmarked; - -@NullUnmarked -@FunctionalInterface -public interface SafeTriFunction { - - R apply(F first, S second, T third) throws Exception; -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/TripleConsumer.java b/rlib-common/src/main/java/javasabr/rlib/common/function/TripleConsumer.java deleted file mode 100644 index 3b692bcf..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/TripleConsumer.java +++ /dev/null @@ -1,25 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.NullUnmarked; - -/** - * The function. - * - * @param the type parameter - * @param the type parameter - * @param the type parameter - * @author JavaSaBr - */ -@NullUnmarked -@FunctionalInterface -public interface TripleConsumer { - - /** - * Accept. - * - * @param first the first - * @param second the second - * @param third the third - */ - void accept(F first, S second, T third); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/TripleFunction.java b/rlib-common/src/main/java/javasabr/rlib/common/function/TripleFunction.java deleted file mode 100644 index 148c9af4..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/TripleFunction.java +++ /dev/null @@ -1,27 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.NullUnmarked; - -/** - * The function. - * - * @param the type parameter - * @param the type parameter - * @param the type parameter - * @param the type parameter - * @author JavaSaBr - */ -@NullUnmarked -@FunctionalInterface -public interface TripleFunction { - - /** - * Apply r. - * - * @param first the first - * @param second the second - * @param third the third - * @return the r - */ - R apply(F first, S second, T third); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/TriplePredicate.java b/rlib-common/src/main/java/javasabr/rlib/common/function/TriplePredicate.java deleted file mode 100644 index 01edb66a..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/TriplePredicate.java +++ /dev/null @@ -1,18 +0,0 @@ -package javasabr.rlib.common.function; - -import org.jspecify.annotations.NullUnmarked; - -@NullUnmarked -@FunctionalInterface -public interface TriplePredicate { - - /** - * Test boolean. - * - * @param first the first - * @param second the second - * @param third the third - * @return the boolean - */ - boolean test(F first, S second, T third); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/function/package-info.java b/rlib-common/src/main/java/javasabr/rlib/common/function/package-info.java deleted file mode 100644 index 61ee1040..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/function/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package javasabr.rlib.common.function; - -import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/rlib-common/src/main/java/javasabr/rlib/common/tuple/IntRefTuple.java b/rlib-common/src/main/java/javasabr/rlib/common/tuple/IntRefTuple.java index 4fd7fce2..4abd05c7 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/tuple/IntRefTuple.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/tuple/IntRefTuple.java @@ -1,3 +1,11 @@ package javasabr.rlib.common.tuple; +/** + * A tuple containing an int value and an object reference. + * + * @param left the int value + * @param right the object reference + * @param the type of the object reference + * @since 10.0.0 + */ public record IntRefTuple(int left, R right) {} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/tuple/LongRefTuple.java b/rlib-common/src/main/java/javasabr/rlib/common/tuple/LongRefTuple.java index 766e10ca..f28282c9 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/tuple/LongRefTuple.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/tuple/LongRefTuple.java @@ -1,3 +1,11 @@ package javasabr.rlib.common.tuple; +/** + * A tuple containing a long value and an object reference. + * + * @param left the long value + * @param right the object reference + * @param the type of the object reference + * @since 10.0.0 + */ public record LongRefTuple(long left, R right) {} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/tuple/Tuple.java b/rlib-common/src/main/java/javasabr/rlib/common/tuple/Tuple.java index 2b9d76bf..012f970e 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/tuple/Tuple.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/tuple/Tuple.java @@ -1,3 +1,12 @@ package javasabr.rlib.common.tuple; +/** + * A tuple containing two object references. + * + * @param left the left value + * @param right the right value + * @param the type of the left value + * @param the type of the right value + * @since 10.0.0 + */ public record Tuple(L left, R right) {} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/AliasedEnumMap.java b/rlib-common/src/main/java/javasabr/rlib/common/util/AliasedEnumMap.java index 4e18da6d..10958599 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/AliasedEnumMap.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/AliasedEnumMap.java @@ -8,12 +8,27 @@ import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; +/** + * Maps string aliases to enum constants for enums implementing {@link AliasedEnum}. + *

+ * Provides efficient lookup of enum constants by their aliases. Throws an exception + * during construction if duplicate aliases are detected. + * + * @param the enum type that implements AliasedEnum + * @since 10.0.0 + */ @CustomLog @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class AliasedEnumMap & AliasedEnum> { Map aliasToValue; + /** + * Creates a new alias map for the specified enum class. + * + * @param enumClass the enum class to create the map for + * @throws IllegalArgumentException if duplicate aliases are detected + */ public AliasedEnumMap(Class enumClass) { var enumConstants = enumClass.getEnumConstants(); var aliasToValue = new HashMap(); @@ -32,16 +47,36 @@ public AliasedEnumMap(Class enumClass) { this.aliasToValue = Map.copyOf(aliasToValue); } + /** + * Resolves an enum constant by its alias. + * + * @param alias the alias to look up + * @return the enum constant, or null if not found + */ @Nullable public T resolve(String alias) { return aliasToValue.get(alias); } + /** + * Resolves an enum constant by its alias, returning a default if not found. + * + * @param alias the alias to look up + * @param def the default value to return if not found + * @return the enum constant, or the default value if not found + */ public T resolve(String alias, T def) { T resolved = resolve(alias); return resolved == null ? def : resolved; } + /** + * Resolves an enum constant by its alias, throwing if not found. + * + * @param alias the alias to look up + * @return the enum constant + * @throws IllegalArgumentException if no constant matches the alias + */ public T require(String alias) { T constant = resolve(alias); if (constant == null) { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java index 029f506e..3c59e552 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java @@ -11,21 +11,18 @@ import java.util.function.IntFunction; import java.util.function.Predicate; import java.util.function.Supplier; -import javasabr.rlib.common.function.CharSupplier; -import javasabr.rlib.common.function.DoubleObjectConsumer; -import javasabr.rlib.common.function.ObjectLongPredicate; -import javasabr.rlib.common.function.TripleConsumer; -import javasabr.rlib.common.function.TripleFunction; -import javasabr.rlib.common.function.TriplePredicate; -import org.jspecify.annotations.NullMarked; +import javasabr.rlib.functions.CharSupplier; +import javasabr.rlib.functions.DoubleObjConsumer; +import javasabr.rlib.functions.TriConsumer; +import javasabr.rlib.functions.TriFunction; +import javasabr.rlib.functions.TriPredicate; import org.jspecify.annotations.Nullable; /** - * The utility class. + * Utility class for array operations including creation, manipulation, searching, and conversion. * - * @author JavaSaBr + * @since 10.0.0 */ -@NullMarked public final class ArrayUtils { public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; @@ -40,35 +37,39 @@ public final class ArrayUtils { public static final long[] EMPTY_LONG_ARRAY = new long[0]; public static final char[] EMPTY_CHAR_ARRAY = new char[0]; + /** + * Creates an array from the given elements. + * + * @param the element type. + * @param elements the elements. + * @return the array containing the elements. + * @since 10.0.0 + */ @SafeVarargs public static T[] array(T... elements) { return elements; } /** - * Convert an object integer array to primitive int array. + * Converts an object integer array to primitive int array. * - * @param array the object integer array. + * @param origin the object integer array. * @return the primitive int array. * @since 9.2.1 */ - public static int[] toIntArray(Integer[] array) { - - if (array.length < 1) { + public static int[] toIntArray(Integer[] origin) { + if (origin.length < 1) { return ArrayUtils.EMPTY_INT_ARRAY; } - - var intArray = new int[array.length]; - - for (int i = 0; i < array.length; i++) { - intArray[i] = array[i]; + var result = new int[origin.length]; + for (int i = 0; i < origin.length; i++) { + result[i] = origin[i]; } - - return intArray; + return result; } /** - * Convert an string to primitive int array by regex. + * Converts a string to primitive int array by splitting with regex. * * @param string the string. * @param regex the regex. @@ -77,66 +78,59 @@ public static int[] toIntArray(Integer[] array) { * @since 9.2.1 */ public static int[] toIntArray(String string, String regex) { - if (string.isBlank()) { return ArrayUtils.EMPTY_INT_ARRAY; } - - var elements = string.split(regex); - + String[] elements = string.split(regex); if (elements.length < 1) { return ArrayUtils.EMPTY_INT_ARRAY; } - var intArray = new int[elements.length]; - for (int i = 0; i < elements.length; i++) { intArray[i] = Integer.parseInt(elements[i].trim()); } - return intArray; } /** - * Add the element to the array and extend or create the array if need. + * Adds an element to the array and extends or creates the array if needed. * - * @param the type parameter + * @param the element type. * @param array the array. * @param element the element. * @param type the type of array. * @return the result array with added element. + * @since 10.0.0 */ public static T[] addToArray(T @Nullable [] array, T element, Class type) { - if (array == null) { array = create(type, 1); array[0] = element; return array; } - int length = array.length; - array = copyOfAndExtend(array, 1); array[length] = element; - return array; } /** - * Clear all elements in the array. + * Clears all elements in the array by setting them to null. * * @param array the array. + * @since 10.0.0 */ public static void clear(Object[] array) { Arrays.fill(array, null); } /** - * Fill the array using the factory. + * Fills the array using the factory. * + * @param the element type. * @param array the array. - * @param factory the element's factory. - * @param the element's type. + * @param factory the element factory. + * @since 10.0.0 */ public static void fill(T[] array, Supplier factory) { for (int i = 0; i < array.length; i++) { @@ -145,10 +139,10 @@ public static void fill(T[] array, Supplier factory) { } /** - * Fill the array using the factory. + * Fills the char array using the factory. * * @param array the array. - * @param factory the element's factory. + * @param factory the element factory. * @since 8.1.0 */ public static void fill(char[] array, CharSupplier factory) { @@ -158,187 +152,178 @@ public static void fill(char[] array, CharSupplier factory) { } /** - * Fill the array using the factory which receives array's index. + * Fills the array using the factory which receives array index. * + * @param the element type. * @param array the array. - * @param factory the element's factory. - * @param the element's type. + * @param factory the element factory. + * @since 10.0.0 */ public static void fill(T[] array, IntFunction factory) { Arrays.setAll(array, factory); } /** - * Fill the array using the factory. + * Fills the array using the factory with an additional argument. * - * @param the element's type. - * @param the argument's type. + * @param the element type. + * @param the argument type. * @param array the array. - * @param argument the additional argument. - * @param factory the element's factory. + * @param arg the additional argument. + * @param factory the element factory. + * @since 10.0.0 */ - public static void fill(T[] array, @Nullable F argument, Function factory) { + public static void fill(T[] array, A arg, Function factory) { for (int i = 0; i < array.length; i++) { - array[i] = factory.apply(argument); + array[i] = factory.apply(arg); } } /** - * Combine the two arrays. + * Combines two int arrays into one. * * @param base the source array. - * @param added the add array. + * @param added the additional array. * @return the combined array. + * @since 10.0.0 */ public static int[] combine(int @Nullable [] base, int @Nullable [] added) { - if (base == null) { return added == null ? new int[0] : added; } else if (added == null || added.length < 1) { return base; } - - final int[] result = new int[base.length + added.length]; - + int[] result = new int[base.length + added.length]; int index = 0; - - for (int val : base) + for (int val : base) { result[index++] = val; - for (int val : added) + } + for (int val : added) { result[index++] = val; - + } return result; } /** - * Combine two arrays to one single array. + * Combines two arrays to one single array. * - * @param the base array's component type. - * @param the added array's component type. + * @param the base array component type. + * @param the added array component type. * @param base the base array. * @param added the additional array. * @return the combined array. + * @since 10.0.0 */ public static T[] combine(T[] base, E @Nullable [] added) { - return combine(base, added, getComponentType(base)); + return combine(base, added, resolveComponentType(base)); } /** - * Combine two arrays to one single array. + * Combines two arrays to one single array. * - * @param the base array's component type. - * @param the added array's component type. + * @param the base array component type. + * @param the added array component type. * @param base the base array. * @param added the additional array. - * @param type the base array's component type. + * @param type the base array component type. * @return the combined array. + * @since 10.0.0 */ public static T[] combine(T @Nullable [] base, E @Nullable [] added, Class type) { - if (base == null) { return added == null ? create(type, 0) : added; } else if (added == null || added.length < 1) { return base; } - T[] result = create(type, base.length + added.length); - int index = 0; - for (T object : base) { result[index++] = object; } - for (E object : added) { result[index++] = object; } - return result; } /** - * Combine two arrays to one single array with uniq elements. + * Combines two arrays to one single array with unique elements. * - * @param the base array's component type. - * @param the added array's component type. + * @param the base array component type. + * @param the added array component type. * @param base the base array. * @param added the additional array. - * @return the combined array with uniq elements. + * @return the combined array with unique elements. + * @since 10.0.0 */ public static T[] combineUniq(T[] base, E @Nullable [] added) { - return combineUniq(base, added, getComponentType(base)); + return combineUniq(base, added, resolveComponentType(base)); } /** - * Combine two arrays to one single array with uniq elements. + * Combines two arrays to one single array with unique elements. * - * @param the base array's component type. - * @param the added array's component type. + * @param the base array component type. + * @param the added array component type. * @param base the base array. * @param added the additional array. - * @param type the base array's component type. - * @return the combined array with uniq elements. + * @param type the base array component type. + * @return the combined array with unique elements. + * @since 10.0.0 */ - public static T[] combineUniq( - T @Nullable [] base, - E @Nullable [] added, - Class type) { - + public static T[] combineUniq(T @Nullable [] base, E @Nullable [] added, Class type) { if (base == null) { return added == null ? create(type, 0) : added; } else if (added == null || added.length < 1) { return base; } - var result = new HashSet(base.length + added.length); result.addAll(Arrays.asList(base)); result.addAll(Arrays.asList(added)); - return result.toArray(create(type, result.size())); } /** - * Check the array on contains the value. + * Checks if the array contains the value. * * @param array the array. * @param val the value. * @return true if the array contains the value. + * @since 10.0.0 */ public static boolean contains(int[] array, int val) { - for (int value : array) { if (value == val) { return true; } } - return false; } /** - * Return true if an array contains an object. + * Checks if an array contains an object. * * @param array the array. * @param object the object. * @return true if the array contains the object. + * @since 10.0.0 */ public static boolean contains(Object[] array, Object object) { - for (var element : array) { if (Objects.equals(element, object)) { return true; } } - return false; } /** - * Copy and extend the array. + * Copies and extends the byte array. * * @param old the source array. * @param added the added size. * @return the new array. + * @since 10.0.0 */ public static byte[] copyOf(byte[] old, int added) { var copy = new byte[old.length + added]; @@ -347,11 +332,12 @@ public static byte[] copyOf(byte[] old, int added) { } /** - * Copy and extend the array. + * Copies and extends the int array. * * @param old the source array. * @param added the added size. * @return the new array. + * @since 10.0.0 */ public static int[] copyOf(int[] old, int added) { var copy = new int[old.length + added]; @@ -360,11 +346,12 @@ public static int[] copyOf(int[] old, int added) { } /** - * Copy and extend the array. + * Copies and extends the long array. * * @param old the source array. * @param added the added size. * @return the new array. + * @since 10.0.0 */ public static long[] copyOf(long[] old, int added) { var copy = new long[old.length + added]; @@ -373,262 +360,266 @@ public static long[] copyOf(long[] old, int added) { } /** - * Copy a native array. + * Copies a native array. * - * @param the array component's type. + * @param the array component type. * @param original the original array. * @return the new copied native array. + * @since 10.0.0 */ public static T[] copyOf(T[] original) { return Arrays.copyOf(original, original.length); } /** - * Copy an array and extend if need. + * Copies an array and extends if needed. * - * @param the array component's type. + * @param the array component type. * @param original the original array. * @param added the additional size. * @return the new copied array. + * @since 10.0.0 */ public static T[] copyOfAndExtend(T[] original, int added) { return Arrays.copyOf(original, original.length + added); } /** - * Copy and extend the array. + * Copies and extends the array with offset. * - * @param the array component's type. + * @param the array component type. * @param original the source array. * @param offset the start position to copy in new array. * @param added the added size. * @return the new array. + * @since 10.0.0 */ public static T[] copyOf(T[] original, int offset, int added) { - Class newType = original.getClass(); T[] newArray = create(newType.getComponentType(), original.length + added); - System.arraycopy(original, 0, newArray, offset, Math.min(original.length, newArray.length)); - return newArray; } /** - * Copy data form the source array to the destination array. + * Copies data from the source array to the destination array. * * @param source the source array. * @param target the target array. + * @since 10.0.0 */ public static void copyTo(int[] source, int[] target) { System.arraycopy(source, 0, target, 0, source.length); } /** - * Copy data form the source array to the destination array. + * Copies data from the source array to the destination array with offsets. * * @param source the source array. * @param target the target array. * @param sourceOffset the source offset. * @param targetOffset the target offset. * @param length the length of data. + * @since 10.0.0 */ - public static void copyTo( - int[] source, - int[] target, - int sourceOffset, - int targetOffset, - int length) { + public static void copyTo(int[] source, int[] target, int sourceOffset, int targetOffset, int length) { System.arraycopy(source, sourceOffset, target, targetOffset, length); } /** - * Copy a part of the array to a new array. + * Copies a part of the int array to a new array. * * @param original the source array. * @param from the start element. * @param to the last element. * @return the new array. + * @since 10.0.0 */ public static int[] copyOfRange(int[] original, int from, int to) { - - var newLength = to - from; + int newLength = to - from; var copy = new int[newLength]; - System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); - return copy; } /** - * Copy a part of the array to a new array. + * Copies a part of the long array to a new array. * * @param original the source array. * @param from the start element. * @param to the last element. * @return the new array. + * @since 10.0.0 */ public static long[] copyOfRange(long[] original, int from, int to) { - - var newLength = to - from; + int newLength = to - from; var copy = new long[newLength]; - System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); - return copy; } /** - * Copy a part of the array to a new array. + * Copies a part of the array to a new array. * - * @param the type parameter + * @param the array component type. * @param original the source array. * @param from the start element. * @param to the last element. * @return the new array. + * @since 10.0.0 */ public static T[] copyOfRange(T[] original, int from, int to) { return Arrays.copyOfRange(original, from, to); } /** - * Get a component type of an array. + * Gets the component type of an array. * - * @param the array's component type. - * @param example the array's example. + * @param the array component type. + * @param example the array example. * @return the component type. + * @since 10.0.0 */ - public static Class getComponentType(T[] example) { + public static Class resolveComponentType(T[] example) { return ClassUtils.unsafeNNCast(example .getClass() .getComponentType()); } /** - * Create the array by the type. + * Creates an array by the example array type. * - * @param the type parameter - * @param example the array's example. + * @param the array component type. + * @param example the array example. * @param size the size. * @return the new array. + * @since 10.0.0 */ public static T[] create(T[] example, int size) { - return ClassUtils.unsafeCast(java.lang.reflect.Array.newInstance( - example - .getClass() - .getComponentType(), size)); + Class componentType = example + .getClass() + .getComponentType(); + return ClassUtils.unsafeCast(java.lang.reflect.Array.newInstance(componentType, size)); } /** - * Create the array by the type. + * Creates an array by the component type. * - * @param the type parameter + * @param the array component type. * @param type the array type. * @param size the size. * @return the new array. + * @since 10.0.0 */ public static T[] create(Class type, int size) { return ClassUtils.unsafeCast(java.lang.reflect.Array.newInstance(type, size)); } /** - * Find an index of the object in the array. + * Finds an index of the object in the array. * * @param array the array. * @param object the object. - * @return the object's index or -1. + * @return the object index or -1. + * @since 10.0.0 */ public static int indexOf(Object[] array, @Nullable Object object) { - int index = 0; - for (var element : array) { if (Objects.equals(element, object)) { return index; } index++; } - return -1; } /** - * Sort the array. + * Sorts the comparable array. * * @param array the array. + * @since 10.0.0 */ - public static void sort(final Comparable[] array) { + public static void sort(Comparable[] array) { java.util.Arrays.sort(array); } /** - * Sort the array. + * Sorts the int array. * * @param array the array. + * @since 10.0.0 */ public static void sort(int[] array) { java.util.Arrays.sort(array); } /** - * Sort the array. + * Sorts the int array in range. * * @param array the array. * @param fromIndex the start index. * @param toIndex the last index. + * @since 10.0.0 */ public static void sort(int[] array, int fromIndex, int toIndex) { java.util.Arrays.sort(array, fromIndex, toIndex); } /** - * Sort the array. + * Sorts the long array in range. * * @param array the array. * @param fromIndex the start index. * @param toIndex the last index. + * @since 10.0.0 */ public static void sort(long[] array, int fromIndex, int toIndex) { java.util.Arrays.sort(array, fromIndex, toIndex); } /** - * Sort the array. + * Sorts the array using comparator. * - * @param the type parameter + * @param the element type. * @param array the array. * @param comparator the comparator. + * @since 10.0.0 */ public static void sort(T[] array, Comparator comparator) { java.util.Arrays.sort(array, comparator); } /** - * Sort the array. + * Sorts the array in range using comparator. * - * @param the type parameter + * @param the element type. * @param array the array. * @param fromIndex the start index. * @param toIndex the last index. * @param comparator the comparator. + * @since 10.0.0 */ - public static void sort( - T[] array, - int fromIndex, - int toIndex, - Comparator comparator) { + public static void sort(T[] array, int fromIndex, int toIndex, Comparator comparator) { java.util.Arrays.sort(array, fromIndex, toIndex, comparator); } + /** + * Converts the array to a string presentation using custom function. + * + * @param the element type. + * @param array the array. + * @param size the size. + * @param toString the converter function. + * @return the string presentation. + * @since 10.0.0 + */ public static String toString(T[] array, int size, Function toString) { - if (array.length < 1) { return "[]"; } - var builder = new StringBuilder(20); builder.append('['); - for (int i = 0, last = size - 1; i < size; i++) { builder.append(toString.apply(array[i])); if (i == last) { @@ -636,48 +627,47 @@ public static String toString(T[] array, int size, Function toStr } builder.append(", "); } - builder.append(']'); - return builder.toString(); } /** - * Convert the array to a string presentation. + * Converts the int array to a string presentation. * * @param array the array. * @return the string presentation. + * @since 10.0.0 */ public static String toString(int @Nullable [] array) { return toString(array, ", ", true, true); } /** - * Convert the array to a string presentation. + * Converts the int array to a string presentation. * * @param array the array. * @param separator the separator. * @param needType true if need adding type of array. * @param needBrackets true if need adding brackets. * @return the string presentation of the array. + * @since 10.0.0 */ - public static String toString( - int @Nullable [] array, - String separator, - boolean needType, - boolean needBrackets) { + public static String toString(int @Nullable [] array, String separator, boolean needType, boolean needBrackets) { int length = array == null ? 0 : array.length; return toString(array, 0, length, separator, needType, needBrackets); } /** - * Convert the array to a string presentation. + * Converts the int array to a string presentation with range. * * @param array the array. + * @param offset the offset. + * @param length the length. * @param separator the separator. * @param needType true if need adding type of array. * @param needBrackets true if need adding brackets. * @return the string presentation of the array. + * @since 10.0.0 */ public static String toString( int @Nullable [] array, @@ -686,20 +676,16 @@ public static String toString( String separator, boolean needType, boolean needBrackets) { - if (array == null) { array = EMPTY_INT_ARRAY; } - - StringBuilder builder = new StringBuilder(); - + var builder = new StringBuilder(); if (needType) { builder.append("int"); } if (needBrackets) { builder.append('['); } - for (int i = offset, limit = offset + length - 1; i <= limit; i++) { builder.append(array[i]); if (i == limit) { @@ -707,22 +693,23 @@ public static String toString( } builder.append(separator); } - if (needBrackets) { builder.append(']'); } - return builder.toString(); } /** - * Convert the array to a string presentation. + * Converts the long array to a string presentation with range. * * @param array the array. + * @param offset the offset. + * @param length the length. * @param separator the separator. * @param needType true if need adding type of array. * @param needBrackets true if need adding brackets. * @return the string presentation of the array. + * @since 10.0.0 */ public static String toString( long @Nullable [] array, @@ -735,16 +722,13 @@ public static String toString( if (array == null) { array = EMPTY_LONG_ARRAY; } - - StringBuilder builder = new StringBuilder(); - + var builder = new StringBuilder(); if (needType) { - builder.append("int"); + builder.append("long"); } if (needBrackets) { builder.append('['); } - for (int i = offset, limit = offset + length - 1; i <= limit; i++) { builder.append(array[i]); if (i == limit) { @@ -752,77 +736,78 @@ public static String toString( } builder.append(separator); } - if (needBrackets) { builder.append(']'); } - return builder.toString(); } /** - * Convert the array to a string presentation. + * Converts the float array to a string presentation. * * @param array the array. * @return the string presentation. + * @since 10.0.0 */ public static String toString(float @Nullable [] array) { return toString(array, ", ", true, true); } /** - * Convert the array to a string presentation. + * Converts the float array to a string presentation. * * @param array the array. * @param separator the separator. * @param needType true if need adding type of array. * @param needBrackets true if need adding brackets. * @return the string presentation of the array. + * @since 10.0.0 */ - public static String toString( - float @Nullable [] array, - final String separator, - final boolean needType, - final boolean needBrackets) { - + public static String toString(float @Nullable [] array, String separator, boolean needType, boolean needBrackets) { if (array == null) { array = EMPTY_FLOAT_ARRAY; } - - final StringBuilder builder = new StringBuilder(); - + var builder = new StringBuilder(); if (needType) { builder.append("float"); } if (needBrackets) { builder.append('['); } - for (int i = 0, length = array.length - 1; i <= length; i++) { - builder.append(String.valueOf(array[i])); + builder.append(array[i]); if (i == length) { break; } builder.append(separator); } - if (needBrackets) { builder.append(']'); } - return builder.toString(); } /** - * Convert the array to a string presentation. + * Converts the object array to a string presentation. * * @param array the array. * @return the string presentation of the array. + * @since 10.0.0 */ public static String toString(Object @Nullable [] array) { return toString(array, ", ", true, true); } + /** + * Converts the object array to a string presentation. + * + * @param array the array. + * @param separator the separator. + * @param needType true if need adding type of array. + * @param needBrackets true if need adding brackets. + * @return the string presentation of the array. + * @since 10.0.0 + */ public static String toString( @Nullable Object @Nullable [] array, String separator, @@ -831,6 +816,18 @@ public static String toString( return toString(array, 0, array == null ? 0 : array.length, separator, needType, needBrackets); } + /** + * Converts the object array to a string presentation with range. + * + * @param array the array. + * @param start the start. + * @param length the length. + * @param separator the separator. + * @param needType true if need adding type of array. + * @param needBrackets true if need adding brackets. + * @return the string presentation of the array. + * @since 10.0.0 + */ public static String toString( @Nullable Object @Nullable [] array, int start, @@ -838,13 +835,10 @@ public static String toString( String separator, boolean needType, boolean needBrackets) { - if (array == null) { array = EMPTY_OBJECT_ARRAY; } - - final StringBuilder builder = new StringBuilder(); - + var builder = new StringBuilder(); if (needType) { builder.append(array .getClass() @@ -853,7 +847,6 @@ public static String toString( if (needBrackets) { builder.append('['); } - for (int i = start, limit = start + length - 1; i <= limit; i++) { builder.append(array[i]); if (i == limit) { @@ -861,878 +854,727 @@ public static String toString( } builder.append(separator); } - if (needBrackets) { builder.append(']'); } - return builder.toString(); } /** - * Apply the function to each element of the array. + * Applies the function to each element of the array. * - * @param the type parameter + * @param the element type. * @param array the array. - * @param function the function. + * @param consumer the function. + * @since 10.0.0 */ - public static void forEach(T @Nullable [] array, Consumer function) { - if (array == null || array.length < 1) { - return; - } - for (T element : array) { - function.accept(element); + public static void forEach(T @Nullable [] array, Consumer consumer) { + if (isNotEmpty(array)) { + for (T element : array) { + consumer.accept(element); + } } } /** - * Apply the function to each filtered element of the array. + * Applies the function to each filtered element of the array. * - * @param the type parameter + * @param the element type. * @param array the array. * @param condition the condition. - * @param function the function. - */ - public static void forEach( - T @Nullable [] array, - Predicate condition, - Consumer function) { - if (array == null || array.length < 1) { - return; - } - for (T element : array) { - if (condition.test(element)) { - function.accept(element); + * @param consumer the function. + * @since 10.0.0 + */ + public static void forEach(T @Nullable [] array, Predicate condition, Consumer consumer) { + if (isNotEmpty(array)) { + for (T element : array) { + if (condition.test(element)) { + consumer.accept(element); + } } } } /** - * Apply the consumer for each element of the array. + * Applies the consumer for each element of the double array. * - * @param the type parameter + * @param the argument type. * @param array the array. - * @param argument the additional argument. + * @param arg the additional argument. * @param consumer the consumer. + * @since 10.0.0 */ - public static void forEach( - double @Nullable[] array, - @Nullable F argument, - DoubleObjectConsumer consumer) { - if (array == null || array.length < 1) { - return; - } - for (double element : array) { - consumer.accept(element, argument); + public static void forEach(double @Nullable [] array, A arg, DoubleObjConsumer consumer) { + if (isNotEmpty(array)) { + for (double element : array) { + consumer.accept(element, arg); + } } } /** - * Apply the consumer for each element of the array. + * Applies the consumer for each element of the array. * - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the argument type. * @param array the array. - * @param argument the additional argument. + * @param arg the additional argument. * @param consumer the consumer. + * @since 10.0.0 */ - public static void forEach( - T @Nullable [] array, - @Nullable F argument, - BiConsumer consumer) { - if (array == null || array.length < 1) { - return; - } - for (T element : array) { - consumer.accept(element, argument); + public static void forEach(T @Nullable [] array, A arg, BiConsumer consumer) { + if (isNotEmpty(array)) { + for (T element : array) { + consumer.accept(element, arg); + } } + } /** - * Handle elements of the array. + * Handles elements of the array using sub-element getter and final function. * - * @param the type parameter - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the argument type. + * @param the sub-element type. * @param array the array. - * @param argument the additional argument. - * @param getElement the function to get sub element. - * @param finalFunction the final function. - */ - public static void forEach( - T @Nullable [] array, - @Nullable F argument, - Function getElement, - BiConsumer finalFunction) { - if (array == null || array.length < 1) { - return; - } - for (T element : array) { - R subElement = getElement.apply(element); - if (subElement != null) { - finalFunction.accept(subElement, argument); + * @param arg the additional argument. + * @param getter the function to get sub element. + * @param consumer the final function. + * @since 10.0.0 + */ + public static void forEach(T @Nullable [] array, A arg, Function getter, BiConsumer consumer) { + if (isNotEmpty(array)) { + for (T element : array) { + consumer.accept(getter.apply(element), arg); } } } /** - * Apply the function to each filtered element of the array. + * Applies the function to each filtered element of the array. * - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the argument type. * @param array the array. - * @param argument the additional argument. + * @param arg the additional argument. * @param condition the condition. - * @param function the function. - */ - public static void forEach( - T @Nullable [] array, - @Nullable F argument, - Predicate condition, - BiConsumer function) { - if (array == null || array.length < 1) { - return; - } - for (T element : array) { - if (condition.test(element)) { - function.accept(element, argument); + * @param consumer the function. + * @since 10.0.0 + */ + public static void forEach(T @Nullable [] array, A arg, Predicate condition, BiConsumer consumer) { + if (isNotEmpty(array)) { + for (T element : array) { + if (condition.test(element)) { + consumer.accept(element, arg); + } } } } /** - * Apply the function to each filtered element of the array. + * Applies the function to each filtered element of the array using sub-element getter. * - * @param the type parameter - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the sub-element type. + * @param the argument type. * @param array the array. - * @param argument the additional argument. + * @param arg the additional argument. * @param condition the condition. - * @param getElement the function to get sub element. - * @param finalFunction the final function. + * @param getter the function to get sub element. + * @param consumer the final function. + * @since 10.0.0 */ - public static void forEach( + public static void forEach( T @Nullable [] array, - @Nullable F argument, + A arg, Predicate condition, - Function getElement, - BiConsumer finalFunction) { - if (array == null || array.length < 1) { - return; - } - for (T element : array) { - if (!condition.test(element)) { - continue; + Function getter, + BiConsumer consumer) { + if (isNotEmpty(array)) { + for (T element : array) { + if (condition.test(element)) { + consumer.accept(getter.apply(element), arg); + } } - R subElement = getElement.apply(element); - finalFunction.accept(subElement, argument); } } /** - * Apply the function to each element of the array. + * Applies the function to each element of the array with two arguments. * - * @param the type parameter - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the first argument type. + * @param the second argument type. * @param array the array. - * @param first the first argument. - * @param second the second argument. - * @param function the function. - */ - public static void forEach( - T @Nullable [] array, - @Nullable F first, - @Nullable S second, - TripleConsumer function) { - if (array == null || array.length < 1) { - return; - } - for (final T element : array) { - function.accept(element, first, second); + * @param arg1 the first argument. + * @param arg2 the second argument. + * @param consumer the function. + * @since 10.0.0 + */ + public static void forEach(T @Nullable [] array, A arg1, B arg2, TriConsumer consumer) { + if (isNotEmpty(array)) { + for (final T element : array) { + consumer.accept(element, arg1, arg2); + } } } /** - * Apply the function to each sub-element of the array. + * Applies the function to each sub-element of the array with two arguments. * - * @param the type parameter - * @param the type parameter - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the sub-element type. + * @param the first argument type. + * @param the second argument type. * @param array the array. - * @param first the first argument. - * @param second the second argument. - * @param getElement the function to get sub element. - * @param function the function. + * @param arg1 the first argument. + * @param arg2 the second argument. + * @param getter the function to get sub element. + * @param consumer the function. + * @since 10.0.0 */ - public static void forEach( + public static void forEach( T @Nullable [] array, - @Nullable F first, - @Nullable S second, - TripleFunction getElement, - TripleConsumer function) { - if (array == null || array.length < 1) { - return; - } - for (T element : array) { - R subElement = getElement.apply(element, first, second); - function.accept(subElement, first, second); + A arg1, + B arg2, + TriFunction getter, + TriConsumer consumer) { + if (isNotEmpty(array)) { + for (T element : array) { + R subElement = getter.apply(element, arg1, arg2); + consumer.accept(subElement, arg1, arg2); + } } + } /** - * Find an index of the element in the array using condition. + * Finds an index of the element in the array using condition. * - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the argument type. * @param array the array. - * @param argument the argument. + * @param arg the argument. * @param condition the condition. * @return the index of the element or -1. + * @since 10.0.0 */ - public static int indexOf( - T @Nullable [] array, - @Nullable F argument, - BiPredicate condition) { - return indexOf(array, argument, condition, 0, array == null ? 0 : array.length); + public static int indexOf(T @Nullable [] array, A arg, BiPredicate condition) { + return indexOf(array, arg, condition, 0, array == null ? 0 : array.length); } /** - * Find an index of the element in an array using condition in the range. + * Finds an index of the element in an array using condition in the range. * - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the argument type. * @param array the array. - * @param argument the argument. + * @param arg the argument. * @param condition the condition. * @param startIndex the start index. * @param endIndex the end index. * @return the index of the element or -1. + * @since 10.0.0 */ - public static int indexOf( + public static int indexOf( T @Nullable [] array, - @Nullable F argument, - BiPredicate condition, + A arg, + BiPredicate condition, int startIndex, int endIndex) { - if (array == null || array.length < 1) { - return -1; - } - for (int i = startIndex; i < endIndex; i++) { - if (condition.test(array[i], argument)) { - return i; + if (isNotEmpty(array)) { + for (int i = startIndex; i < endIndex; i++) { + if (condition.test(array[i], arg)) { + return i; + } } } return -1; } /** - * Calculate a count of interesting elements of the array. + * Calculates a count of interesting elements of the array. * - * @param the type parameter + * @param the element type. * @param array the array. * @param condition the condition. * @return the count of elements. + * @since 10.0.0 */ public static int count(T @Nullable [] array, Predicate condition) { - if (array == null || array.length < 1) { + if (isEmpty(array)) { return 0; } - int count = 0; - for (T element : array) { if (condition.test(element)) { count++; } } - return count; } /** - * Find an element in the array using the condition. + * Finds an element in the array using the condition. * - * @param the array's element type. + * @param the array element type. * @param array the array. * @param condition the condition. * @return the element or null. - */ - public static @Nullable T findAny(T @Nullable [] array, Predicate condition) { - - if (array == null || array.length < 1) { - return null; - } - - for (T element : array) { - if (condition.test(element)) { - return element; + * @since 10.0.0 + */ + @Nullable + public static T findAny(T @Nullable [] array, Predicate condition) { + if (isNotEmpty(array)) { + for (T element : array) { + if (condition.test(element)) { + return element; + } } } - return null; } /** - * Return true if there is at least an element for the condition. + * Checks if there is at least an element for the condition. * - * @param the array's element type. + * @param the array element type. * @param array the array. * @param condition the condition. * @return true if there is at least an element for the condition. + * @since 10.0.0 */ public static boolean anyMatch(T @Nullable [] array, Predicate condition) { return findAny(array, condition) != null; } /** - * Find an element in the array using the condition. - * - * @param the array's element type. - * @param the argument's type. - * @param array the array. - * @param argument the argument. - * @param condition the condition. - * @return the element or null. - */ - public static @Nullable T findAny( - T @Nullable [] array, - @Nullable F argument, - BiPredicate condition) { - - if (array == null || array.length < 1) { - return null; - } - - for (T element : array) { - if (condition.test(element, argument)) { - return element; - } - } - - return null; - } - - /** - * Find an element in the array using the condition. + * Finds an element in the array using the condition. * - * @param the array's element type. - * @param the argument's type. + * @param the array element type. + * @param the argument type. * @param array the array. - * @param argument the argument. + * @param arg the argument. * @param condition the condition. * @return the element or null. + * @since 10.0.0 */ - public static @Nullable T findAnyR( - T @Nullable [] array, - @Nullable F argument, - BiPredicate<@Nullable F, ? super T> condition) { - - if (array == null || array.length < 1) { + @Nullable + public static T findAny(T @Nullable [] array, A arg, BiPredicate condition) { + if (isEmpty(array)) { return null; } - for (T element : array) { - if (condition.test(argument, element)) { + if (condition.test(element, arg)) { return element; } } - return null; } /** - * Return true if there is at least an element for the condition. + * Checks if there is at least an element for the condition. * - * @param the array's element type. - * @param the argument's type. + * @param the array element type. + * @param the argument type. * @param array the array. - * @param argument the argument. + * @param arg the argument. * @param condition the condition. * @return true if there is at least an element for the condition. + * @since 10.0.0 */ - public static boolean anyMatchR( - T @Nullable [] array, - @Nullable F argument, - BiPredicate<@Nullable F, ? super T> condition) { - return findAnyR(array, argument, condition) != null; + public static boolean anyMatch(T @Nullable [] array, A arg, BiPredicate condition) { + return findAny(array, arg, condition) != null; } /** - * Find a sub-element in the array using the function to get a sub-element + the condition. + * Finds a sub-element in the array using the function to get a sub-element and the condition. * - * @param the type parameter - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the sub-element type. + * @param the argument type. * @param array the array. - * @param argument the argument. - * @param getElement the function to get a sub-element. + * @param arg the argument. + * @param getter the function to get a sub-element. * @param condition the condition. * @return the element or null. + * @since 10.0.0 */ - public static @Nullable R findAny( - T @Nullable [] array, - @Nullable F argument, - Function getElement, - BiPredicate condition) { - - if (array == null || array.length < 1) { + @Nullable + public static R findAny(T @Nullable [] array, A arg, Function getter, BiPredicate condition) { + if (isEmpty(array)) { return null; } - for (T element : array) { - R subElement = getElement.apply(element); - if (condition.test(subElement, argument)) { + R subElement = getter.apply(element); + if (condition.test(subElement, arg)) { return subElement; } } - return null; } /** - * Find a sub-element in the array using the function to get a sub-element + conditions. + * Finds a sub-element in the array using the function to get a sub-element and conditions. * - * @param the type parameter - * @param the type parameter - * @param the type parameter + * @param the element type. + * @param the sub-element type. + * @param the argument type. * @param array the array. - * @param argument the argument. + * @param arg the argument. * @param condition the condition. - * @param getElement the function to get a sub-element. - * @param secondCond the second cond + * @param getter the function to get a sub-element. + * @param secondCondition the second condition. * @return the element or null. + * @since 10.0.0 */ - public static @Nullable R findAny( + @Nullable + public static R findAny( T @Nullable [] array, - @Nullable F argument, + A arg, Predicate condition, - Function getElement, - BiPredicate secondCond) { - - if (array == null || array.length < 1) { + Function getter, + BiPredicate secondCondition) { + if (isEmpty(array)) { return null; } - for (T element : array) { - if (!condition.test(element)) { continue; } - - R subElement = getElement.apply(element); - if (secondCond.test(subElement, argument)) { - return subElement; - } - } - - return null; - } - - /** - * Find a sub-element in the array using the function to get a sub-element + conditions. - * - * @param the type parameter - * @param the type parameter - * @param array the array. - * @param argument the argument. - * @param firstCond the first condition. - * @param getElement the function to get a sub-element. - * @param secondCond the second condition. - * @return the element or null. - */ - public static @Nullable R findL( - T @Nullable [] array, - long argument, - Predicate firstCond, - Function getElement, - ObjectLongPredicate secondCond) { - - if (array == null || array.length < 1) { - return null; - } - - for (T element : array) { - - if (!firstCond.test(element)) { - continue; - } - - R subElement = getElement.apply(element); - - if (secondCond.test(subElement, argument)) { + R subElement = getter.apply(element); + if (secondCondition.test(subElement, arg)) { return subElement; } } - return null; } /** - * Find an element in the array using the condition. + * Finds an element in the array using the condition with two arguments. * - * @param the type parameter + * @param the element type. + * @param the first argument type. + * @param the second argument type. * @param array the array. - * @param argument the argument. + * @param arg1 the first argument. + * @param arg2 the second argument. * @param condition the condition. * @return the element or null. - */ - public static @Nullable T findL( - T @Nullable [] array, - long argument, - ObjectLongPredicate condition) { - - if (array == null || array.length < 1) { - return null; - } - - for (final T element : array) { - if (condition.test(element, argument)) { - return element; + * @since 10.0.0 + */ + @Nullable + public static T findAny(T @Nullable [] array, F arg1, S arg2, TriPredicate condition) { + if (isNotEmpty(array)) { + for (T element : array) { + if (condition.test(element, arg1, arg2)) { + return element; + } } } - return null; } /** - * Find an element in the array using the condition. - * - * @param the type parameter - * @param the type parameter - * @param array the array. - * @param argument the argument. - * @param getElement the get element - * @param condition the condition. - * @return the element or null. - */ - public static @Nullable R findL( - T @Nullable [] array, - long argument, - Function getElement, - ObjectLongPredicate condition) { - - if (array == null || array.length < 1) { - return null; - } - - for (T element : array) { - R subElement = getElement.apply(element); - if (condition.test(subElement, argument)) { - return subElement; - } - } - - return null; - } - - /** - * Find an element in the array using the condition. - * - * @param the type parameter - * @param the type parameter - * @param the type parameter - * @param array the array. - * @param first the first argument. - * @param second the second argument. - * @param condition the condition. - * @return the element or null. - */ - public static @Nullable T findAny( - T @Nullable [] array, - @Nullable F first, - @Nullable S second, - TriplePredicate condition) { - - if (array == null || array.length < 1) { - return null; - } - - for (T element : array) { - if (condition.test(element, first, second)) { - return element; - } - } - - return null; - } - - /** - * Return true if the array is not null or empty. + * Checks if the byte array is not null or empty. * * @param array the array. * @return true if the array is not null or empty. + * @since 10.0.0 */ public static boolean isNotEmpty(byte @Nullable [] array) { return array != null && array.length > 0; } /** - * Return true if the array is null or empty. + * Checks if the byte array is null or empty. * * @param array the array. * @return true if the array is null or empty. + * @since 10.0.0 */ public static boolean isEmpty(byte @Nullable [] array) { return array == null || array.length == 0; } /** - * Return true if the array is not null or empty. + * Checks if the short array is not null or empty. * * @param array the array. * @return true if the array is not null or empty. + * @since 10.0.0 */ public static boolean isNotEmpty(short @Nullable [] array) { return array != null && array.length > 0; } /** - * Return true if the array is null or empty. + * Checks if the short array is null or empty. * * @param array the array. * @return true if the array is null or empty. + * @since 10.0.0 */ public static boolean isEmpty(short @Nullable [] array) { return array == null || array.length == 0; } /** - * Return true if the array is not null or empty. + * Checks if the char array is not null or empty. * * @param array the array. * @return true if the array is not null or empty. + * @since 10.0.0 */ public static boolean isNotEmpty(char @Nullable [] array) { return array != null && array.length > 0; } /** - * Return true if the array is null or empty. + * Checks if the char array is null or empty. * * @param array the array. * @return true if the array is null or empty. + * @since 10.0.0 */ public static boolean isEmpty(char @Nullable [] array) { return array == null || array.length == 0; } /** - * Return true if the array is not null or empty. + * Checks if the int array is not null or empty. * * @param array the array. * @return true if the array is not null or empty. + * @since 10.0.0 */ public static boolean isNotEmpty(int @Nullable [] array) { return array != null && array.length > 0; } /** - * Return true if the array is null or empty. + * Checks if the int array is null or empty. * * @param array the array. * @return true if the array is null or empty. + * @since 10.0.0 */ public static boolean isEmpty(int @Nullable [] array) { return array == null || array.length == 0; } /** - * Return true if the array is not null or empty. + * Checks if the long array is not null or empty. * * @param array the array. * @return true if the array is not null or empty. + * @since 10.0.0 */ public static boolean isNotEmpty(long @Nullable [] array) { return array != null && array.length > 0; } /** - * Return true if the array is null or empty. + * Checks if the long array is null or empty. * * @param array the array. * @return true if the array is null or empty. + * @since 10.0.0 */ public static boolean isEmpty(long @Nullable [] array) { return array == null || array.length == 0; } /** - * Return true if the array is not null or empty. + * Checks if the float array is not null or empty. * * @param array the array. * @return true if the array is not null or empty. + * @since 10.0.0 */ public static boolean isNotEmpty(float @Nullable [] array) { return array != null && array.length > 0; } /** - * Return true if the array is null or empty. + * Checks if the float array is null or empty. * * @param array the array. * @return true if the array is null or empty. + * @since 10.0.0 */ public static boolean isEmpty(float @Nullable [] array) { return array == null || array.length == 0; } /** - * Return true if the array is not null or empty. + * Checks if the double array is not null or empty. * * @param array the array. * @return true if the array is not null or empty. + * @since 10.0.0 */ public static boolean isNotEmpty(double @Nullable [] array) { return array != null && array.length > 0; } /** - * Return true if the array is null or empty. + * Checks if the double array is null or empty. * * @param array the array. * @return true if the array is null or empty. + * @since 10.0.0 */ public static boolean isEmpty(double @Nullable [] array) { return array == null || array.length == 0; } /** - * Return true if the array is not null or empty. + * Checks if the object array is not null or empty. * * @param array the array. * @return true if the array is not null or empty. + * @since 10.0.0 */ public static boolean isNotEmpty(Object @Nullable [] array) { return array != null && array.length > 0; } /** - * Return true if the array is null or empty. + * Checks if the object array is null or empty. * * @param array the array. * @return true if the array is null or empty. + * @since 10.0.0 */ public static boolean isEmpty(Object @Nullable [] array) { return array == null || array.length == 0; } /** - * Convert T array to R array. + * Returns the length of the byte array or 0 if null. * - * @param the source component type. - * @param the mapped element's type. - * @param the result element's type. - * @param source the source array. - * @param mapper the mapper. - * @param resultType the result component type. - * @return the mapped array. - * @since 9.5.0 + * @param array the array. + * @return the length or 0. + * @since 10.0.0 */ - public static R @Nullable [] map( - T [] source, - Function mapper, - Class resultType) { - - if (source.length == 0) { - return create(resultType, 0); - } - - R[] resultArray = create(resultType, source.length); - - for (int i = 0; i < source.length; i++) { - resultArray[i] = mapper.apply(source[i]); - } + public static int length(byte @Nullable [] array) { + return array == null ? 0 : array.length; + } - return resultArray; + /** + * Returns the length of the short array or 0 if null. + * + * @param array the array. + * @return the length or 0. + * @since 10.0.0 + */ + public static int length(short @Nullable [] array) { + return array == null ? 0 : array.length; } /** - * Convert T array to R array. + * Returns the length of the int array or 0 if null. * - * @param the source component type. - * @param the mapped element's type. - * @param the result element's type. - * @param source the source array. - * @param mapper the mapper. - * @param def the default result if source array is null. - * @return the mapped array. - * @since 9.5.0 + * @param array the array. + * @return the length or 0. + * @since 10.0.0 */ - public static R [] map( - T @Nullable [] source, - Function mapper, - R[] def) { + public static int length(int @Nullable [] array) { + return array == null ? 0 : array.length; + } - if (source == null || source.length == 0) { - return def; - } + /** + * Returns the length of the long array or 0 if null. + * + * @param array the array. + * @return the length or 0. + * @since 10.0.0 + */ + public static int length(long @Nullable [] array) { + return array == null ? 0 : array.length; + } - R[] resultArray = create( - def - .getClass() - .getComponentType(), source.length); + /** + * Returns the length of the float array or 0 if null. + * + * @param array the array. + * @return the length or 0. + * @since 10.0.0 + */ + public static int length(float @Nullable [] array) { + return array == null ? 0 : array.length; + } - for (int i = 0; i < source.length; i++) { - resultArray[i] = mapper.apply(source[i]); - } + /** + * Returns the length of the double array or 0 if null. + * + * @param array the array. + * @return the length or 0. + * @since 10.0.0 + */ + public static int length(double @Nullable [] array) { + return array == null ? 0 : array.length; + } - return resultArray; + /** + * Returns the length of the object array or 0 if null. + * + * @param array the array. + * @return the length or 0. + * @since 10.0.0 + */ + public static int length(Object @Nullable [] array) { + return array == null ? 0 : array.length; } /** - * Convert T array to R array if a source array is not null. + * Converts T array to R array using mapper. * * @param the source component type. - * @param the mapped element's type. - * @param the result element's type. + * @param the mapped element type. + * @param the result element type. * @param source the source array. * @param mapper the mapper. * @param resultType the result component type. - * @return the mapped array or null. - * @since 9.3.0 + * @return the mapped array. + * @since 9.5.0 */ - public static R @Nullable [] mapNullable( - T @Nullable [] source, - Function mapper, - Class resultType) { - - if (source == null) { - return null; - } else if (source.length == 0) { + public static R @Nullable [] map(T[] source, Function mapper, Class resultType) { + if (isEmpty(source)) { return create(resultType, 0); } - R[] resultArray = create(resultType, source.length); - for (int i = 0; i < source.length; i++) { resultArray[i] = mapper.apply(source[i]); } - return resultArray; } /** - * Convert long array to int array. + * Converts T array to R array using mapper with default value. * + * @param the source component type. + * @param the mapped element type. + * @param the result element type. * @param source the source array. - * @return the int array. - * @since 9.3.0 + * @param mapper the mapper. + * @param def the default result if source array is null. + * @return the mapped array. + * @since 9.5.0 */ - public static int [] longsToInts(long[] source) { - - if (source.length == 0) { - return ArrayUtils.EMPTY_INT_ARRAY; + public static R[] map(T @Nullable [] source, Function mapper, R[] def) { + if (isEmpty(source)) { + return def; } - - var resultArray = new int[source.length]; - + Class componentType = def + .getClass() + .getComponentType(); + R[] resultArray = create(componentType, source.length); for (int i = 0; i < source.length; i++) { - resultArray[i] = (int) source[i]; + resultArray[i] = mapper.apply(source[i]); } - return resultArray; } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/AsyncUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/AsyncUtils.java index 16fa0e9c..0e8566a7 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/AsyncUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/AsyncUtils.java @@ -6,16 +6,37 @@ import org.jspecify.annotations.Nullable; /** - * @author JavaSaBr + * Utility methods for asynchronous programming and CompletionStage handling. + * + * @since 10.0.0 */ @UtilityClass public class AsyncUtils { + /** + * A utility method that ignores the throwable and returns null. + *

+ * Useful as an exception handler in CompletionStage chains. + * + * @param the expected result type + * @param throwable the throwable to skip + * @return always null + */ @Nullable public static T skip(Throwable throwable) { return null; } + /** + * Continues a CompletionStage by either returning the result or throwing an exception. + * + * @param the result type + * @param result the result value, required if throwable is null + * @param throwable the exception, if any + * @return the result if no exception occurred + * @throws RuntimeException if throwable is a RuntimeException + * @throws CompletionException if throwable is any other exception + */ public static T continueCompletableStage(@Nullable T result, @Nullable Throwable throwable) { if (throwable instanceof RuntimeException) { throw (RuntimeException) throwable; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/BufferUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/BufferUtils.java index 25ae6b5e..e76056dc 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/BufferUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/BufferUtils.java @@ -13,7 +13,9 @@ import org.jspecify.annotations.NullMarked; /** - * @author JavaSaBr + * Utility methods for working with NIO byte buffers. + * + * @since 10.0.0 */ @NullMarked @UtilityClass @@ -68,6 +70,13 @@ public static MappedByteBuffer allocateRWMappedByteBuffer(int size) { } } + /** + * Puts additional buffer content into the buffer and flips it. + * + * @param buffer the target buffer + * @param additional the buffer to append + * @return the flipped buffer + */ public static ByteBuffer putToAndFlip(ByteBuffer buffer, ByteBuffer additional) { return buffer .limit(buffer.capacity()) @@ -75,6 +84,13 @@ public static ByteBuffer putToAndFlip(ByteBuffer buffer, ByteBuffer additional) .flip(); } + /** + * Appends additional buffer content to the buffer and clears the additional buffer. + * + * @param buffer the target buffer + * @param additional the buffer to append + * @return the flipped buffer + */ public static ByteBuffer appendAndClear(ByteBuffer buffer, ByteBuffer additional) { ByteBuffer result = buffer .position(buffer.limit()) @@ -86,11 +102,11 @@ public static ByteBuffer appendAndClear(ByteBuffer buffer, ByteBuffer additional } /** - * Create a new byte buffer with writing some data inside the consumer and to flip in the result. + * Creates a new byte buffer with writing some data inside the consumer and to flip in the result. * - * @param size the buffer's size. - * @param consumer the consumer to write data. - * @return the flipped buffer. + * @param size the buffer's size + * @param consumer the consumer to write data + * @return the flipped buffer */ public static ByteBuffer prepareBuffer(int size, Consumer consumer) { var buffer = ByteBuffer.allocate(size); diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/ClassUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/ClassUtils.java index f7c54be4..76f94b2c 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/ClassUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/ClassUtils.java @@ -10,13 +10,21 @@ import org.jspecify.annotations.Nullable; /** - * The class with utility methods. + * Utility methods for class and constructor operations. * - * @author JavaSaBr + * @since 10.0.0 */ @NullMarked public final class ClassUtils { + /** + * Finds the common super type of two objects. + * + * @param the common type + * @param e1 the first object + * @param e2 the second object + * @return the common super class + */ public static Class commonType(E e1, E e2) { Class type = e1.getClass(); while (!type.isInstance(e2)) { @@ -25,6 +33,15 @@ public static Class commonType(E e1, E e2) { return (Class) type; } + /** + * Finds the common super type of three objects. + * + * @param the common type + * @param e1 the first object + * @param e2 the second object + * @param e3 the third object + * @return the common super class + */ public static Class commonType(E e1, E e2, E e3) { Class type = e1.getClass(); while (!type.isInstance(e2) || !type.isInstance(e3)) { @@ -33,6 +50,16 @@ public static Class commonType(E e1, E e2, E e3) { return (Class) type; } + /** + * Finds the common super type of four objects. + * + * @param the common type + * @param e1 the first object + * @param e2 the second object + * @param e3 the third object + * @param e4 the fourth object + * @return the common super class + */ public static Class commonType(E e1, E e2, E e3, E e4) { Class type = e1.getClass(); while (!type.isInstance(e2) || !type.isInstance(e3) || !type.isInstance(e4)) { @@ -41,6 +68,17 @@ public static Class commonType(E e1, E e2, E e3, E e4) { return (Class) type; } + /** + * Finds the common super type of five objects. + * + * @param the common type + * @param e1 the first object + * @param e2 the second object + * @param e3 the third object + * @param e4 the fourth object + * @param e5 the fifth object + * @return the common super class + */ public static Class commonType(E e1, E e2, E e3, E e4, E e5) { Class type = e1.getClass(); while (!type.isInstance(e2) || !type.isInstance(e3) || !type.isInstance(e4) || !type.isInstance(e5)) { @@ -49,6 +87,18 @@ public static Class commonType(E e1, E e2, E e3, E e4, E e5) { return (Class) type; } + /** + * Finds the common super type of six objects. + * + * @param the common type + * @param e1 the first object + * @param e2 the second object + * @param e3 the third object + * @param e4 the fourth object + * @param e5 the fifth object + * @param e6 the sixth object + * @return the common super class + */ public static Class commonType(E e1, E e2, E e3, E e4, E e5, E e6) { Class type = e1.getClass(); while (!type.isInstance(e2) || !type.isInstance(e3) || !type.isInstance(e4) || !type.isInstance(e5) || !type.isInstance(e6)) { @@ -57,6 +107,12 @@ public static Class commonType(E e1, E e2, E e3, E e4, E e5, E e6) { return (Class) type; } + /** + * Finds the common super type of multiple objects. + * + * @param objects the objects to find common type for + * @return the common super class, or Object.class if empty + */ public static Class commonType(Object... objects) { if (objects.length < 1) { return Object.class; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/CycleBuffer.java b/rlib-common/src/main/java/javasabr/rlib/common/util/CycleBuffer.java index a14333e0..18573799 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/CycleBuffer.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/CycleBuffer.java @@ -6,47 +6,39 @@ import org.jspecify.annotations.Nullable; /** - * The implementation of cycle buffer of some objects. + * A circular buffer that cycles through pre-allocated objects. + *

+ * Useful for reusing objects in hot paths to reduce garbage collection overhead. * - * @param the type parameter - * @author JavaSaBr + * @param the type of objects in the buffer + * @since 10.0.0 */ @NullMarked public final class CycleBuffer { - /** - * The array with buffered objects. - */ private final T[] buffer; - - /** - * The handler of getting object from buffer. - */ private final @Nullable Consumer handler; - - /** - * The index of next object. - */ private int order; /** - * Instantiates a new Cycle buffer. + * Creates a new cycle buffer. * - * @param type the type - * @param size the size - * @param factory the factory + * @param type the element type + * @param size the buffer size (must be at least 2) + * @param factory the factory to create elements */ public CycleBuffer(final Class type, final int size, final Supplier factory) { this(type, size, factory, null); } /** - * Instantiates a new Cycle buffer. + * Creates a new cycle buffer with an optional handler. * - * @param type the type - * @param size the size - * @param factory the factory - * @param handler the handler + * @param type the element type + * @param size the buffer size (must be at least 2) + * @param factory the factory to create elements + * @param handler optional handler called when retrieving an element + * @throws RuntimeException if size is less than 2 */ public CycleBuffer( Class type, @@ -68,9 +60,9 @@ public CycleBuffer( } /** - * Get a next free object. + * Returns the next object from the buffer, cycling back to the start when the end is reached. * - * @return the next free object. + * @return the next object from the buffer */ public T next() { if (order >= buffer.length) { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/DateUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/DateUtils.java index b96f3a7f..d47baf67 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/DateUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/DateUtils.java @@ -12,9 +12,9 @@ import org.jspecify.annotations.Nullable; /** - * The class with utility methods to work with dates and times. + * Utility methods for working with dates and times. * - * @author JavaSaBr + * @since 9.3.0 */ @NullMarked public class DateUtils { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/ExtMath.java b/rlib-common/src/main/java/javasabr/rlib/common/util/ExtMath.java index b8ffb6c9..ac42d059 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/ExtMath.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/ExtMath.java @@ -4,9 +4,9 @@ import org.jspecify.annotations.Nullable; /** - * The utility class. + * Extended math utility methods including float-based trigonometry and epsilon comparisons. * - * @author JavaSaBr + * @since 10.0.0 */ @NullMarked public final class ExtMath { @@ -16,14 +16,10 @@ public final class ExtMath { public static final Integer ZERO_INTEGER = 0; public static final Long ZERO_LONG = 0L; - /** - * The value PI as a float. (180 degrees). - */ + /** PI as a float (180 degrees). */ public static final float PI = (float) Math.PI; - /** - * The value PI/2 as a float. (90 degrees) - */ + /** PI/2 as a float (90 degrees). */ public static final float HALF_PI = 0.5f * PI; public static final double EPSILON = 1.40129846432482E-45; @@ -115,166 +111,166 @@ public static float sin(float value) { } /** - * Returns the square root of a given value. + * Returns the square root of a value. * - * @param value The value to sqrt. - * @return The square root of the given value. - * @see java.lang.Math#sqrt(double) java.lang.Math#sqrt(double) + * @param value the value to sqrt + * @return the square root of the value + * @see java.lang.Math#sqrt(double) */ public static float sqrt(float value) { return (float) Math.sqrt(value); } /** - * Return true of the value is zero. + * Returns true if the value is zero. * - * @param value the value. - * @return true if the values are equals. + * @param value the value + * @return true if the value is zero */ public static boolean isZero(float value) { return Float.compare(value, 0F) == 0; } /** - * Return true of the value is zero. + * Returns true if the value is zero. * - * @param value the value. - * @return true if the values are equals. + * @param value the value + * @return true if the value is zero */ public static boolean isZero(double value) { return Double.compare(value, 0D) == 0; } /** - * Compare the two float values. + * Compares two float values for equality. * - * @param first the first. - * @param second the second. - * @return true if the values are equals. + * @param first the first value + * @param second the second value + * @return true if the values are equal */ public static boolean equals(float first, float second) { return Float.compare(first, second) == 0; } /** - * Compare the two float values. + * Compares two double values for equality. * - * @param first the first. - * @param second the second. - * @return true if the values are equals. + * @param first the first value + * @param second the second value + * @return true if the values are equal */ public static boolean equals(double first, double second) { return Double.compare(first, second) == 0; } /** - * Compare the two float values by the epsilon. + * Compares two float values for equality within an epsilon tolerance. * - * @param first the first. - * @param second the second. - * @param epsilon the epsilon. - * @return true if the values are equals. + * @param first the first value + * @param second the second value + * @param epsilon the tolerance + * @return true if the values are equal within the epsilon */ public static boolean equals(float first, float second, float epsilon) { return first == second || Math.abs(first - second) < epsilon; } /** - * Compare the two float values by the epsilon. + * Compares two double values for equality within an epsilon tolerance. * - * @param first the first. - * @param second the second. - * @param epsilon the epsilon. - * @return true if the values are equals. + * @param first the first value + * @param second the second value + * @param epsilon the tolerance + * @return true if the values are equal within the epsilon */ public static boolean equals(double first, double second, double epsilon) { return first == second || Math.abs(first - second) < epsilon; } /** - * Compare the two float values by the epsilon. + * Checks if the first float value is less than the second within an epsilon tolerance. * - * @param first the first. - * @param second the second. - * @param epsilon the epsilon. - * @return true if the first value is less than the second value. + * @param first the first value + * @param second the second value + * @param epsilon the tolerance + * @return true if the first value is less than the second */ public static boolean lessThan(float first, float second, float epsilon) { return second - first > epsilon; } /** - * Compare the two float values by the epsilon. + * Checks if the first double value is less than the second within an epsilon tolerance. * - * @param first the first. - * @param second the second. - * @param epsilon the epsilon. - * @return true if the first value is less than the second value. + * @param first the first value + * @param second the second value + * @param epsilon the tolerance + * @return true if the first value is less than the second */ public static boolean lessThan(double first, double second, double epsilon) { return second - first > epsilon; } /** - * Compare the two float values by the epsilon. + * Checks if the first float value is greater than the second within an epsilon tolerance. * - * @param first the first. - * @param second the second. - * @param epsilon the epsilon. - * @return true if the first value is greater than the second value. + * @param first the first value + * @param second the second value + * @param epsilon the tolerance + * @return true if the first value is greater than the second */ public static boolean greaterThan(float first, float second, float epsilon) { return first - second > epsilon; } /** - * Compare the two float values by the epsilon. + * Checks if the first double value is greater than the second within an epsilon tolerance. * - * @param first the first. - * @param second the second. - * @param epsilon the epsilon. - * @return true if the first value is greater than the second value. + * @param first the first value + * @param second the second value + * @param epsilon the tolerance + * @return true if the first value is greater than the second */ public static boolean greaterThan(double first, double second, double epsilon) { return first - second > epsilon; } /** - * Cut the second part of the float value by the mod. For example: cut(1.123456F, 3) returns 1.123F. + * Truncates a float value to a specified precision. For example: cut(1.123456F, 1000) returns 1.123F. * - * @param value the value. - * @param mod the mod. - * @return the cut value. + * @param value the value to truncate + * @param mod the precision modifier + * @return the truncated value */ public static float cut(float value, float mod) { return (int) (value * mod) / mod; } /** - * Return zero if the value is null. + * Returns zero if the value is null. * - * @param value the value. - * @return zero if the value is null. + * @param value the value + * @return zero if the value is null, otherwise the value */ public static Float zeroIfNull(@Nullable Float value) { return value == null ? ZERO_FLOAT : value; } /** - * Return zero if the value is null. + * Returns zero if the value is null. * - * @param value the value. - * @return zero if the value is null. + * @param value the value + * @return zero if the value is null, otherwise the value */ public static Double zeroIfNull(@Nullable Double value) { return value == null ? ZERO_DOUBLE : value; } /** - * Return zero if the value is null. + * Returns zero if the value is null. * - * @param value the value. - * @return zero if the value is null. + * @param value the value + * @return zero if the value is null, otherwise the value */ public static Integer zeroIfNull(@Nullable Integer value) { return value == null ? ZERO_INTEGER : value; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/GroupThreadFactory.java b/rlib-common/src/main/java/javasabr/rlib/common/util/GroupThreadFactory.java index e41f0beb..17832bd4 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/GroupThreadFactory.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/GroupThreadFactory.java @@ -6,13 +6,28 @@ import lombok.experimental.FieldDefaults; /** - * @author JavaSaBr + * A thread factory that creates threads within a named thread group. + * + * @since 10.0.0 */ @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public class GroupThreadFactory implements ThreadFactory { + /** + * Functional interface for custom thread construction. + * + * @since 10.0.0 + */ public interface ThreadConstructor { + /** + * Creates a new thread. + * + * @param group the thread group + * @param runnable the runnable to execute + * @param name the thread name + * @return the new thread + */ Thread create(ThreadGroup group, Runnable runnable, String name); } @@ -24,18 +39,44 @@ public interface ThreadConstructor { int priority; boolean daemon; + /** + * Creates a factory with normal priority threads. + * + * @param name the base name for threads + */ public GroupThreadFactory(String name) { this(name, Thread::new, Thread.NORM_PRIORITY); } + /** + * Creates a factory with specified priority threads. + * + * @param name the base name for threads + * @param priority the thread priority + */ public GroupThreadFactory(String name, int priority) { this(name, Thread::new, priority); } + /** + * Creates a factory with custom thread constructor and priority. + * + * @param name the base name for threads + * @param constructor the thread constructor + * @param priority the thread priority + */ public GroupThreadFactory(String name, ThreadConstructor constructor, int priority) { this(name, constructor, priority, false); } + /** + * Creates a factory with full configuration. + * + * @param name the base name for threads + * @param constructor the thread constructor + * @param priority the thread priority + * @param daemon whether threads should be daemon threads + */ public GroupThreadFactory(String name, ThreadConstructor constructor, int priority, boolean daemon) { this.constructor = constructor; this.priority = priority; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/NumberUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/NumberUtils.java index 7df5b60e..3b5afcc1 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/NumberUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/NumberUtils.java @@ -6,9 +6,9 @@ import org.jspecify.annotations.Nullable; /** - * The utility class. + * Utility methods for numeric operations including parsing, bit manipulation, and conversion. * - * @author JavaSaBr + * @since 9.3.0 */ @NullMarked public final class NumberUtils { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/NumberedEnum.java b/rlib-common/src/main/java/javasabr/rlib/common/util/NumberedEnum.java index 32e802a1..e1a04d3f 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/NumberedEnum.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/NumberedEnum.java @@ -1,6 +1,17 @@ package javasabr.rlib.common.util; +/** + * Marks an enum whose constants have a numeric identifier. + * + * @param the concrete enum type implementing this interface + * @since 10.0.0 + */ public interface NumberedEnum> { + /** + * Returns the numeric identifier for this enum constant. + * + * @return the number associated with this constant + */ int number(); } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/NumberedEnumMap.java b/rlib-common/src/main/java/javasabr/rlib/common/util/NumberedEnumMap.java index 8a8cd29d..7d533ae3 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/NumberedEnumMap.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/NumberedEnumMap.java @@ -6,12 +6,25 @@ import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; +/** + * Maps numeric identifiers to enum constants for enums implementing {@link NumberedEnum}. + *

+ * Provides efficient lookup of enum constants by their number. + * + * @param the enum type that implements NumberedEnum + * @since 10.0.0 + */ @CustomLog @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class NumberedEnumMap & NumberedEnum> { T[] values; + /** + * Creates a new number map for the specified enum class. + * + * @param enumClass the enum class to create the map for + */ public NumberedEnumMap(Class enumClass) { T[] enumConstants = enumClass.getEnumConstants(); @@ -29,6 +42,12 @@ public NumberedEnumMap(Class enumClass) { values = indexedConstants; } + /** + * Resolves an enum constant by its number. + * + * @param number the number to look up + * @return the enum constant, or null if not found + */ @Nullable public T resolve(int number) { try { @@ -39,11 +58,25 @@ public T resolve(int number) { } } + /** + * Resolves an enum constant by its number, returning a default if not found. + * + * @param number the number to look up + * @param def the default value to return if not found + * @return the enum constant, or the default value if not found + */ public T resolve(int number, T def) { T resolved = resolve(number); return resolved == null ? def : resolved; } + /** + * Resolves an enum constant by its number, throwing if not found. + * + * @param number the number to look up + * @return the enum constant + * @throws IllegalArgumentException if no constant matches the number + */ public T require(int number) { T constant = resolve(number); if (constant == null) { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/ObjectUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/ObjectUtils.java index 303cdf2d..26ba5852 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/ObjectUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/ObjectUtils.java @@ -8,9 +8,9 @@ import org.jspecify.annotations.Nullable; /** - * The class with utility methods. + * Utility methods for null-checking and hashing objects. * - * @author JavaSaBr + * @since 9.0.2 */ @NullMarked public final class ObjectUtils { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/PropertyLoader.java b/rlib-common/src/main/java/javasabr/rlib/common/util/PropertyLoader.java index f7f9608a..6c72a134 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/PropertyLoader.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/PropertyLoader.java @@ -12,12 +12,19 @@ import org.jspecify.annotations.Nullable; /** - * @author JavaSaBr + * Resource bundle control that loads properties files as UTF-8. + * + * @since 10.0.0 */ public final class PropertyLoader extends ResourceBundle.Control { private static final PropertyLoader INSTANCE = new PropertyLoader(); + /** + * Returns the singleton instance. + * + * @return the property loader instance + */ public static PropertyLoader getInstance() { return INSTANCE; } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/ReflectionUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/ReflectionUtils.java index 5cc648dd..297dd40e 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/ReflectionUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/ReflectionUtils.java @@ -12,7 +12,9 @@ import org.jspecify.annotations.Nullable; /** - * @author JavaSaBr + * Utility methods for Java reflection operations. + * + * @since 10.0.0 */ @UtilityClass public final class ReflectionUtils { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/StringUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/StringUtils.java index 3c2bcfbc..8eeadff2 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/StringUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/StringUtils.java @@ -11,9 +11,9 @@ import org.jspecify.annotations.Nullable; /** - * The class with utility methods for working with strings. + * Utility methods for string operations including validation, comparison, and generation. * - * @author JavaSaBr + * @since 10.0.0 */ @NullMarked public class StringUtils { @@ -27,32 +27,32 @@ public class StringUtils { private static final ThreadLocal LOCAL_HASH_MD = ThreadLocal.withInitial(StringUtils::getHashMD5); /** - * Return an empty string if the received string is null. + * Returns an empty string if the received string is null. * - * @param string the string. - * @return an empty string if the received string is null. + * @param string the string + * @return an empty string if the received string is null */ public static String emptyIfNull(@Nullable String string) { return string == null ? EMPTY : string; } /** - * Return the another string if the received string is empty or null. + * Returns the alternative string if the received string is empty or null. * - * @param string the string. - * @param another the another string. - * @return the another string if the received string is empty or null. + * @param string the string + * @param another the alternative string + * @return the alternative string if the received string is empty or null */ public static String ifEmpty(@Nullable String string, String another) { return isEmpty(string) ? another : string; } /** - * Return the another string if the received string is blank or null. + * Returns the alternative string if the received string is blank or null. * - * @param string the string. - * @param another the another string. - * @return the another string if the received string is blank or null. + * @param string the string + * @param another the alternative string + * @return the alternative string if the received string is blank or null */ public static String ifBlank(@Nullable String string, String another) { return isBlank(string) ? another : string; diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/ThreadUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/ThreadUtils.java index e6d9269f..fa96c3ee 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/ThreadUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/ThreadUtils.java @@ -4,12 +4,19 @@ import javasabr.rlib.logger.api.LoggerManager; /** - * @author JavaSaBr + * Utility methods for thread operations. + * + * @since 10.0.0 */ public class ThreadUtils { private static final Logger LOGGER = LoggerManager.getLogger(ThreadUtils.class); + /** + * Sleeps the current thread for the specified time, ignoring interrupts. + * + * @param time the time to sleep in milliseconds + */ public static void sleep(long time) { try { Thread.sleep(time); diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/Utils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/Utils.java index 9d80939e..3cae0fdf 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/Utils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/Utils.java @@ -8,19 +8,21 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.Callable; -import javasabr.rlib.common.function.NotNullSafeBiConsumer; -import javasabr.rlib.common.function.NotNullSafeBiFunction; -import javasabr.rlib.common.function.NotNullSafeConsumer; -import javasabr.rlib.common.function.NotNullSafeFunction; -import javasabr.rlib.common.function.NotNullSafeSupplier; -import javasabr.rlib.common.function.NotNullSafeTriFunction; -import javasabr.rlib.common.function.SafeRunnable; +import javasabr.rlib.functions.SafeBiConsumer; +import javasabr.rlib.functions.SafeBiFunction; +import javasabr.rlib.functions.SafeConsumer; +import javasabr.rlib.functions.SafeFunction; +import javasabr.rlib.functions.SafeRunnable; +import javasabr.rlib.functions.SafeSupplier; +import javasabr.rlib.functions.SafeTriFunction; import javasabr.rlib.logger.api.LoggerManager; import lombok.experimental.UtilityClass; import org.jspecify.annotations.Nullable; /** - * @author JavaSaBr + * General utility methods for file operations and exception handling. + * + * @since 10.0.0 */ @UtilityClass public final class Utils { @@ -113,7 +115,7 @@ public static void unchecked(SafeRunnable function) { } } - public static @Nullable R tryGet(NotNullSafeSupplier function) { + public static @Nullable R tryGet(SafeSupplier function) { try { return function.get(); } catch (Exception e) { @@ -122,7 +124,7 @@ public static void unchecked(SafeRunnable function) { } } - public static void unchecked(F first, NotNullSafeConsumer function) { + public static void unchecked(F first, SafeConsumer function) { try { function.accept(first); } catch (IOException e) { @@ -135,7 +137,7 @@ public static void unchecked(F first, NotNullSafeConsumer function) { public static void unchecked( F first, S second, - NotNullSafeBiConsumer consumer) { + SafeBiConsumer consumer) { try { consumer.accept(first, second); } catch (IOException e) { @@ -155,7 +157,7 @@ public static R uncheckedGet(Callable function) { } } - public static R uncheckedGet(F argument, NotNullSafeFunction function) { + public static R uncheckedGet(F argument, SafeFunction function) { try { return function.apply(argument); } catch (IOException e) { @@ -167,7 +169,7 @@ public static R uncheckedGet(F argument, NotNullSafeFunction functi public static R uncheckedGet( F argument, - NotNullSafeFunction function, + SafeFunction function, R def) { try { return function.apply(argument); @@ -179,7 +181,7 @@ public static R uncheckedGet( public static R uncheckedGet( F first, S second, - NotNullSafeBiFunction function) { + SafeBiFunction function) { try { return function.apply(first, second); } catch (IOException e) { @@ -192,7 +194,7 @@ public static R uncheckedGet( F first, S second, T third, - NotNullSafeTriFunction function) { + SafeTriFunction function) { try { return function.apply(first, second, third); } catch (IOException e) { @@ -202,7 +204,7 @@ public static R uncheckedGet( } } - public static @Nullable R tryGet(F argument, NotNullSafeFunction function) { + public static @Nullable R tryGet(F argument, SafeFunction function) { try { return function.apply(argument); } catch (Exception e) { @@ -213,7 +215,7 @@ public static R uncheckedGet( public static R tryGet( F argument, - NotNullSafeFunction function, + SafeFunction function, R def) { try { return function.apply(argument); @@ -225,8 +227,8 @@ public static R tryGet( public static @Nullable FR tryGetAndConvert( F argument, - NotNullSafeFunction function, - NotNullSafeFunction resultConverter) { + SafeFunction function, + SafeFunction resultConverter) { try { return resultConverter.apply(function.apply(argument)); } catch (Exception e) { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/os/OperatingSystem.java b/rlib-common/src/main/java/javasabr/rlib/common/util/os/OperatingSystem.java index 50b2d797..f08ee9bb 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/os/OperatingSystem.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/os/OperatingSystem.java @@ -4,110 +4,52 @@ import org.jspecify.annotations.Nullable; /** - * THe class with description of an Operation System. + * Represents information about the current operating system. * - * @author JavaSaBr + * @since 10.0.0 */ @NullMarked public class OperatingSystem { - /** - * The name. - */ private String name; - - /** - * The version. - */ private String version; - - /** - * The arch. - */ private String arch; - - /** - * The distribution. - */ private String distribution; - /** - * Instantiates a new Operating system. - */ public OperatingSystem() { final OperatingSystemResolver resolver = new OperatingSystemResolver(); resolver.resolve(this); } - /** - * Gets arch. - * - * @return the arch. - */ public String getArch() { return arch; } - /** - * Sets arch. - * - * @param arch the arch. - */ public void setArch(final String arch) { this.arch = arch; } - /** - * Gets distribution. - * - * @return the distribution. - */ @Nullable public String getDistribution() { return distribution; } - /** - * Sets distribution. - * - * @param distribution the distribution. - */ public void setDistribution(@Nullable final String distribution) { this.distribution = distribution; } - /** - * Gets name. - * - * @return the name. - */ public String getName() { return name; } - /** - * Sets name. - * - * @param name the name. - */ public void setName(final String name) { this.name = name; } - /** - * Gets version. - * - * @return the version. - */ public String getVersion() { return version; } - /** - * Sets version. - * - * @param version the version. - */ public void setVersion(final String version) { this.version = version; } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/os/OperatingSystemResolver.java b/rlib-common/src/main/java/javasabr/rlib/common/util/os/OperatingSystemResolver.java index 162e29c3..b5f361a8 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/os/OperatingSystemResolver.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/os/OperatingSystemResolver.java @@ -15,45 +15,21 @@ import org.jspecify.annotations.NullMarked; /** - * THe resolver of OS information. + * Resolves operating system information from system properties and configuration files. * - * @author JavaSaBr + * @since 10.0.0 */ @NullMarked public class OperatingSystemResolver { - /** - * The constant FILE_PROC_VERSION. - */ public static final String FILE_PROC_VERSION = "/proc/version"; - /** - * The constant FILE_ETC_ISSUE. - */ public static final String FILE_ETC_ISSUE = "/etc/issue"; - /** - * The constant FILE_ETC. - */ public static final String FILE_ETC = "/etc/"; - /** - * The constant FILE_ETC_SYSTEM_RELEASE. - */ public static final String FILE_ETC_SYSTEM_RELEASE = "/etc/system-release"; - /** - * The constant FILE_ETC_LSB_RELEASE. - */ public static final String FILE_ETC_LSB_RELEASE = "/etc/lsb-release"; - /** - * The constant PROP_PRETTY_NAME. - */ public static final String PROP_PRETTY_NAME = "PRETTY_NAME"; - /** - * The constant PROP_DISTRIB_CODENAME. - */ public static final String PROP_DISTRIB_CODENAME = "DISTRIB_CODENAME"; - /** - * The constant PROP_DISTRIB_DESCRIPTION. - */ public static final String PROP_DISTRIB_DESCRIPTION = "DISTRIB_DESCRIPTION"; private static final String NAME = System.getProperty("os.name"); diff --git a/rlib-common/src/test/java/javasabr/rlib/common/util/ArrayUtilsTest.java b/rlib-common/src/test/java/javasabr/rlib/common/util/ArrayUtilsTest.java new file mode 100644 index 00000000..ffc31718 --- /dev/null +++ b/rlib-common/src/test/java/javasabr/rlib/common/util/ArrayUtilsTest.java @@ -0,0 +1,1016 @@ +package javasabr.rlib.common.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Predicate; +import org.junit.jupiter.api.Test; + +public class ArrayUtilsTest { + + // ==================== length tests ==================== + + @Test + void shouldReturnCorrectLength() { + // when/then: + assertThat(ArrayUtils.length((byte[]) null)).isEqualTo(0); + assertThat(ArrayUtils.length((short[]) null)).isEqualTo(0); + assertThat(ArrayUtils.length((int[]) null)).isEqualTo(0); + assertThat(ArrayUtils.length((long[]) null)).isEqualTo(0); + assertThat(ArrayUtils.length((float[]) null)).isEqualTo(0); + assertThat(ArrayUtils.length((double[]) null)).isEqualTo(0); + assertThat(ArrayUtils.length((Object[]) null)).isEqualTo(0); + // when/then: + assertThat(ArrayUtils.length(new byte[]{1, 2})).isEqualTo(2); + assertThat(ArrayUtils.length(new short[]{1, 2})).isEqualTo(2); + assertThat(ArrayUtils.length(new int[]{1, 2})).isEqualTo(2); + assertThat(ArrayUtils.length(new long[]{1, 2})).isEqualTo(2); + assertThat(ArrayUtils.length(new float[]{1, 2})).isEqualTo(2); + assertThat(ArrayUtils.length(new double[]{1, 2})).isEqualTo(2); + assertThat(ArrayUtils.length(new Object[]{1, 2})).isEqualTo(2); + } + + // ==================== isEmpty tests ==================== + + @Test + void shouldCheckIfArrayIsEmpty() { + // when/then: null arrays + assertThat(ArrayUtils.isEmpty((byte[]) null)).isTrue(); + assertThat(ArrayUtils.isEmpty((short[]) null)).isTrue(); + assertThat(ArrayUtils.isEmpty((char[]) null)).isTrue(); + assertThat(ArrayUtils.isEmpty((int[]) null)).isTrue(); + assertThat(ArrayUtils.isEmpty((long[]) null)).isTrue(); + assertThat(ArrayUtils.isEmpty((float[]) null)).isTrue(); + assertThat(ArrayUtils.isEmpty((double[]) null)).isTrue(); + assertThat(ArrayUtils.isEmpty((Object[]) null)).isTrue(); + // when/then: non-empty arrays + assertThat(ArrayUtils.isEmpty(new byte[]{1, 2})).isFalse(); + assertThat(ArrayUtils.isEmpty(new short[]{1, 2})).isFalse(); + assertThat(ArrayUtils.isEmpty(new char[]{'a', 'b'})).isFalse(); + assertThat(ArrayUtils.isEmpty(new int[]{1, 2})).isFalse(); + assertThat(ArrayUtils.isEmpty(new long[]{1, 2})).isFalse(); + assertThat(ArrayUtils.isEmpty(new float[]{1, 2})).isFalse(); + assertThat(ArrayUtils.isEmpty(new double[]{1, 2})).isFalse(); + assertThat(ArrayUtils.isEmpty(new Object[]{1, 2})).isFalse(); + // when/then: empty arrays + assertThat(ArrayUtils.isEmpty(new byte[]{})).isTrue(); + assertThat(ArrayUtils.isEmpty(new short[]{})).isTrue(); + assertThat(ArrayUtils.isEmpty(new char[]{})).isTrue(); + assertThat(ArrayUtils.isEmpty(new int[]{})).isTrue(); + assertThat(ArrayUtils.isEmpty(new long[]{})).isTrue(); + assertThat(ArrayUtils.isEmpty(new float[]{})).isTrue(); + assertThat(ArrayUtils.isEmpty(new double[]{})).isTrue(); + assertThat(ArrayUtils.isEmpty(new Object[]{})).isTrue(); + } + + // ==================== isNotEmpty tests ==================== + + @Test + void shouldCheckIfArrayIsNotEmpty() { + // when/then: null arrays + assertThat(ArrayUtils.isNotEmpty((byte[]) null)).isFalse(); + assertThat(ArrayUtils.isNotEmpty((short[]) null)).isFalse(); + assertThat(ArrayUtils.isNotEmpty((char[]) null)).isFalse(); + assertThat(ArrayUtils.isNotEmpty((int[]) null)).isFalse(); + assertThat(ArrayUtils.isNotEmpty((long[]) null)).isFalse(); + assertThat(ArrayUtils.isNotEmpty((float[]) null)).isFalse(); + assertThat(ArrayUtils.isNotEmpty((double[]) null)).isFalse(); + assertThat(ArrayUtils.isNotEmpty((Object[]) null)).isFalse(); + // when/then: non-empty arrays + assertThat(ArrayUtils.isNotEmpty(new byte[]{1, 2})).isTrue(); + assertThat(ArrayUtils.isNotEmpty(new short[]{1, 2})).isTrue(); + assertThat(ArrayUtils.isNotEmpty(new char[]{'a', 'b'})).isTrue(); + assertThat(ArrayUtils.isNotEmpty(new int[]{1, 2})).isTrue(); + assertThat(ArrayUtils.isNotEmpty(new long[]{1, 2})).isTrue(); + assertThat(ArrayUtils.isNotEmpty(new float[]{1, 2})).isTrue(); + assertThat(ArrayUtils.isNotEmpty(new double[]{1, 2})).isTrue(); + assertThat(ArrayUtils.isNotEmpty(new Object[]{1, 2})).isTrue(); + // when/then: empty arrays + assertThat(ArrayUtils.isNotEmpty(new byte[]{})).isFalse(); + assertThat(ArrayUtils.isNotEmpty(new short[]{})).isFalse(); + assertThat(ArrayUtils.isNotEmpty(new char[]{})).isFalse(); + assertThat(ArrayUtils.isNotEmpty(new int[]{})).isFalse(); + assertThat(ArrayUtils.isNotEmpty(new long[]{})).isFalse(); + assertThat(ArrayUtils.isNotEmpty(new float[]{})).isFalse(); + assertThat(ArrayUtils.isNotEmpty(new double[]{})).isFalse(); + assertThat(ArrayUtils.isNotEmpty(new Object[]{})).isFalse(); + } + + // ==================== array creation tests ==================== + + @Test + void shouldCreateArrayFromVarargs() { + // when: + String[] result = ArrayUtils.array("a", "b", "c"); + // then: + assertThat(result).containsExactly("a", "b", "c"); + } + + @Test + void shouldCreateArrayByExample() { + // given: + String[] example = new String[]{"x"}; + // when: + String[] result = ArrayUtils.create(example, 3); + // then: + assertThat(result).hasSize(3); + assertThat(result).containsOnlyNulls(); + } + + @Test + void shouldCreateArrayByType() { + // when: + String[] result = ArrayUtils.create(String.class, 5); + // then: + assertThat(result).hasSize(5); + assertThat(result).containsOnlyNulls(); + } + + @Test + void shouldResolveComponentType() { + // given: + String[] array = new String[]{"a", "b"}; + // when: + Class componentType = ArrayUtils.resolveComponentType(array); + // then: + assertThat(componentType).isEqualTo(String.class); + } + + // ==================== toIntArray tests ==================== + + @Test + void shouldConvertIntegerArrayToIntArray() { + // given: + Integer[] integers = {1, 2, 3, 4, 5}; + // when: + int[] result = ArrayUtils.toIntArray(integers); + // then: + assertThat(result).containsExactly(1, 2, 3, 4, 5); + } + + @Test + void shouldReturnEmptyIntArrayForEmptyIntegerArray() { + // when: + int[] result = ArrayUtils.toIntArray(new Integer[]{}); + // then: + assertThat(result).isEmpty(); + } + + @Test + void shouldParseStringToIntArray() { + // when: + int[] result = ArrayUtils.toIntArray("1, 2, 3, 4", ","); + // then: + assertThat(result).containsExactly(1, 2, 3, 4); + } + + @Test + void shouldReturnEmptyIntArrayForBlankString() { + // when: + int[] result = ArrayUtils.toIntArray(" ", ","); + // then: + assertThat(result).isEmpty(); + } + + @Test + void shouldThrowExceptionForInvalidIntegerString() { + // when/then: + assertThatThrownBy(() -> ArrayUtils.toIntArray("1, abc, 3", ",")) + .isInstanceOf(NumberFormatException.class); + } + + // ==================== addToArray tests ==================== + + @Test + void shouldAddElementToNullArray() { + // when: + String[] result = ArrayUtils.addToArray(null, "element", String.class); + // then: + assertThat(result).containsExactly("element"); + } + + @Test + void shouldAddElementToExistingArray() { + // given: + String[] array = {"a", "b"}; + // when: + String[] result = ArrayUtils.addToArray(array, "c", String.class); + // then: + assertThat(result).containsExactly("a", "b", "c"); + } + + // ==================== clear tests ==================== + + @Test + void shouldClearArray() { + // given: + Object[] array = {"a", "b", "c"}; + // when: + ArrayUtils.clear(array); + // then: + assertThat(array).containsOnlyNulls(); + } + + // ==================== fill tests ==================== + + @Test + void shouldFillArrayWithSupplier() { + // given: + String[] array = new String[3]; + AtomicInteger counter = new AtomicInteger(0); + // when: + ArrayUtils.fill(array, () -> "item" + counter.incrementAndGet()); + // then: + assertThat(array).containsExactly("item1", "item2", "item3"); + } + + @Test + void shouldFillCharArrayWithSupplier() { + // given: + char[] array = new char[3]; + AtomicInteger counter = new AtomicInteger('a' - 1); + // when: + ArrayUtils.fill(array, () -> (char) counter.incrementAndGet()); + // then: + assertThat(array).containsExactly('a', 'b', 'c'); + } + + @Test + void shouldFillArrayWithIntFunction() { + // given: + Integer[] array = new Integer[4]; + // when: + ArrayUtils.fill(array, i -> i * 2); + // then: + assertThat(array).containsExactly(0, 2, 4, 6); + } + + @Test + void shouldFillArrayWithFunctionAndArgument() { + // given: + String[] array = new String[3]; + // when: + ArrayUtils.fill(array, "prefix_", arg -> arg + "value"); + // then: + assertThat(array).containsExactly("prefix_value", "prefix_value", "prefix_value"); + } + + // ==================== combine tests ==================== + + @Test + void shouldCombineIntArrays() { + // when: + int[] result = ArrayUtils.combine(new int[]{1, 2}, new int[]{3, 4}); + // then: + assertThat(result).containsExactly(1, 2, 3, 4); + } + + @Test + void shouldHandleNullBaseIntArray() { + // when: + int[] result = ArrayUtils.combine(null, new int[]{1, 2}); + // then: + assertThat(result).containsExactly(1, 2); + } + + @Test + void shouldHandleNullAddedIntArray() { + // when: + int[] result = ArrayUtils.combine(new int[]{1, 2}, null); + // then: + assertThat(result).containsExactly(1, 2); + } + + @Test + void shouldCombineObjectArrays() { + // when: + String[] result = ArrayUtils.combine(new String[]{"a", "b"}, new String[]{"c", "d"}); + // then: + assertThat(result).containsExactly("a", "b", "c", "d"); + } + + @Test + void shouldCombineObjectArraysWithType() { + // when: + String[] result = ArrayUtils.combine( + new String[]{"a"}, + new String[]{"b"}, + String.class + ); + // then: + assertThat(result).containsExactly("a", "b"); + } + + @Test + void shouldCombineArraysWithUniqElements() { + // when: + String[] result = ArrayUtils.combineUniq( + new String[]{"a", "b", "c"}, + new String[]{"b", "c", "d"} + ); + // then: + assertThat(result).containsExactlyInAnyOrder("a", "b", "c", "d"); + } + + @Test + void shouldCombineArraysWithUniqElementsAndType() { + // when: + String[] result = ArrayUtils.combineUniq( + new String[]{"a", "a", "b"}, + new String[]{"b", "c"}, + String.class + ); + // then: + assertThat(result).containsExactlyInAnyOrder("a", "b", "c"); + } + + // ==================== contains tests ==================== + + @Test + void shouldCheckIfIntArrayContainsValue() { + // given: + int[] array = {1, 2, 3, 4, 5}; + // when/then: + assertThat(ArrayUtils.contains(array, 3)).isTrue(); + assertThat(ArrayUtils.contains(array, 10)).isFalse(); + } + + @Test + void shouldCheckIfObjectArrayContainsElement() { + // given: + String[] array = {"a", "b", "c"}; + // when/then: + assertThat(ArrayUtils.contains(array, "b")).isTrue(); + assertThat(ArrayUtils.contains(array, "x")).isFalse(); + } + + // ==================== copyOf tests ==================== + + @Test + void shouldCopyAndExtendByteArray() { + // given: + byte[] original = {1, 2, 3}; + // when: + byte[] result = ArrayUtils.copyOf(original, 2); + // then: + assertThat(result).hasSize(5); + assertThat(result).containsExactly((byte) 1, (byte) 2, (byte) 3, (byte) 0, (byte) 0); + } + + @Test + void shouldCopyAndExtendIntArray() { + // given: + int[] original = {1, 2, 3}; + // when: + int[] result = ArrayUtils.copyOf(original, 2); + // then: + assertThat(result).hasSize(5); + assertThat(result).containsExactly(1, 2, 3, 0, 0); + } + + @Test + void shouldCopyAndExtendLongArray() { + // given: + long[] original = {1L, 2L, 3L}; + // when: + long[] result = ArrayUtils.copyOf(original, 2); + // then: + assertThat(result).hasSize(5); + assertThat(result).containsExactly(1L, 2L, 3L, 0L, 0L); + } + + @Test + void shouldCopyObjectArray() { + // given: + String[] original = {"a", "b", "c"}; + // when: + String[] result = ArrayUtils.copyOf(original); + // then: + assertThat(result).containsExactly("a", "b", "c"); + assertThat(result).isNotSameAs(original); + } + + @Test + void shouldCopyAndExtendObjectArray() { + // given: + String[] original = {"a", "b"}; + // when: + String[] result = ArrayUtils.copyOfAndExtend(original, 2); + // then: + assertThat(result).hasSize(4); + assertThat(result).containsExactly("a", "b", null, null); + } + + @Test + void shouldCopyObjectArrayWithOffset() { + // given: + String[] original = {"a", "b", "c"}; + // when: + String[] result = ArrayUtils.copyOf(original, 1, 2); + // then: + assertThat(result).hasSize(5); + assertThat(result[0]).isNull(); + assertThat(result[1]).isEqualTo("a"); + assertThat(result[2]).isEqualTo("b"); + assertThat(result[3]).isEqualTo("c"); + } + + // ==================== copyTo tests ==================== + + @Test + void shouldCopyToTargetArray() { + // given: + int[] source = {1, 2, 3}; + int[] target = new int[5]; + // when: + ArrayUtils.copyTo(source, target); + // then: + assertThat(target).containsExactly(1, 2, 3, 0, 0); + } + + @Test + void shouldCopyToTargetArrayWithOffsets() { + // given: + int[] source = {1, 2, 3, 4, 5}; + int[] target = new int[5]; + // when: + ArrayUtils.copyTo(source, target, 1, 2, 2); + // then: + assertThat(target).containsExactly(0, 0, 2, 3, 0); + } + + // ==================== copyOfRange tests ==================== + + @Test + void shouldCopyRangeOfIntArray() { + // given: + int[] original = {1, 2, 3, 4, 5}; + // when: + int[] result = ArrayUtils.copyOfRange(original, 1, 4); + // then: + assertThat(result).containsExactly(2, 3, 4); + } + + @Test + void shouldCopyRangeOfLongArray() { + // given: + long[] original = {1L, 2L, 3L, 4L, 5L}; + // when: + long[] result = ArrayUtils.copyOfRange(original, 2, 5); + // then: + assertThat(result).containsExactly(3L, 4L, 5L); + } + + @Test + void shouldCopyRangeOfObjectArray() { + // given: + String[] original = {"a", "b", "c", "d", "e"}; + // when: + String[] result = ArrayUtils.copyOfRange(original, 1, 3); + // then: + assertThat(result).containsExactly("b", "c"); + } + + // ==================== indexOf tests ==================== + + @Test + void shouldFindIndexOfObject() { + // given: + String[] array = {"a", "b", "c", "d"}; + // when/then: + assertThat(ArrayUtils.indexOf(array, "c")).isEqualTo(2); + assertThat(ArrayUtils.indexOf(array, "x")).isEqualTo(-1); + assertThat(ArrayUtils.indexOf(array, null)).isEqualTo(-1); + } + + @Test + void shouldFindIndexOfNullObject() { + // given: + String[] array = {"a", null, "c"}; + // when: + int index = ArrayUtils.indexOf(array, null); + // then: + assertThat(index).isEqualTo(1); + } + + @Test + void shouldFindIndexWithCondition() { + // given: + String[] array = {"apple", "banana", "cherry"}; + // when: + int index = ArrayUtils.indexOf(array, "an", (element, arg) -> element.contains(arg)); + // then: + assertThat(index).isEqualTo(1); + } + + @Test + void shouldFindIndexWithConditionInRange() { + // given: + String[] array = {"apple", "banana", "avocado", "apricot"}; + // when: + int index = ArrayUtils.indexOf(array, "a", (e, arg) -> e.startsWith(arg), 1, 4); + // then: + assertThat(index).isEqualTo(2); + } + + // ==================== sort tests ==================== + + @Test + void shouldSortComparableArray() { + // given: + String[] array = {"c", "a", "b"}; + // when: + ArrayUtils.sort(array); + // then: + assertThat(array).containsExactly("a", "b", "c"); + } + + @Test + void shouldSortIntArray() { + // given: + int[] array = {3, 1, 4, 1, 5}; + // when: + ArrayUtils.sort(array); + // then: + assertThat(array).containsExactly(1, 1, 3, 4, 5); + } + + @Test + void shouldSortIntArrayInRange() { + // given: + int[] array = {5, 3, 1, 4, 2}; + // when: + ArrayUtils.sort(array, 1, 4); + // then: + assertThat(array).containsExactly(5, 1, 3, 4, 2); + } + + @Test + void shouldSortLongArrayInRange() { + // given: + long[] array = {5L, 3L, 1L, 4L, 2L}; + // when: + ArrayUtils.sort(array, 1, 4); + // then: + assertThat(array).containsExactly(5L, 1L, 3L, 4L, 2L); + } + + @Test + void shouldSortArrayWithComparator() { + // given: + String[] array = {"aaa", "b", "cc"}; + // when: + ArrayUtils.sort(array, Comparator.comparingInt(String::length)); + // then: + assertThat(array).containsExactly("b", "cc", "aaa"); + } + + @Test + void shouldSortArrayInRangeWithComparator() { + // given: + String[] array = {"ddd", "a", "cc", "bb"}; + // when: + ArrayUtils.sort(array, 1, 4, Comparator.comparingInt(String::length)); + // then: + assertThat(array).containsExactly("ddd", "a", "cc", "bb"); + } + + // ==================== toString tests ==================== + + @Test + void shouldConvertArrayToStringWithFunction() { + // given: + Integer[] array = {1, 2, 3}; + // when: + String result = ArrayUtils.toString(array, 3, n -> "N" + n); + // then: + assertThat(result).isEqualTo("[N1, N2, N3]"); + } + + @Test + void shouldConvertEmptyArrayToString() { + // given: + Integer[] array = {}; + // when: + String result = ArrayUtils.toString(array, 0, Object::toString); + // then: + assertThat(result).isEqualTo("[]"); + } + + @Test + void shouldConvertIntArrayToString() { + // given: + int[] array = {1, 2, 3}; + // when: + String result = ArrayUtils.toString(array); + // then: + assertThat(result).isEqualTo("int[1, 2, 3]"); + } + + @Test + void shouldConvertIntArrayToStringWithOptions() { + // given: + int[] array = {1, 2, 3}; + // when: + String result = ArrayUtils.toString(array, "-", false, false); + // then: + assertThat(result).isEqualTo("1-2-3"); + } + + @Test + void shouldConvertIntArrayToStringWithRange() { + // given: + int[] array = {1, 2, 3, 4, 5}; + // when: + String result = ArrayUtils.toString(array, 1, 3, ", ", false, true); + // then: + assertThat(result).isEqualTo("[2, 3, 4]"); + } + + @Test + void shouldConvertNullIntArrayToString() { + // when: + String result = ArrayUtils.toString((int[]) null); + // then: + assertThat(result).isEqualTo("int[]"); + } + + @Test + void shouldConvertLongArrayToStringWithRange() { + // given: + long[] array = {10L, 20L, 30L, 40L}; + // when: + String result = ArrayUtils.toString(array, 1, 2, "-", false, true); + // then: + assertThat(result).isEqualTo("[20-30]"); + } + + @Test + void shouldConvertFloatArrayToString() { + // given: + float[] array = {1.5f, 2.5f}; + // when: + String result = ArrayUtils.toString(array); + // then: + assertThat(result).isEqualTo("float[1.5, 2.5]"); + } + + @Test + void shouldConvertFloatArrayToStringWithOptions() { + // given: + float[] array = {1.0f, 2.0f}; + // when: + String result = ArrayUtils.toString(array, "|", false, false); + // then: + assertThat(result).isEqualTo("1.0|2.0"); + } + + @Test + void shouldConvertObjectArrayToString() { + // given: + String[] array = {"a", "b"}; + // when: + String result = ArrayUtils.toString(array); + // then: + assertThat(result).isEqualTo("String[][a, b]"); + } + + @Test + void shouldConvertObjectArrayToStringWithOptions() { + // given: + String[] array = {"a", "b", "c"}; + // when: + String result = ArrayUtils.toString(array, "-", false, true); + // then: + assertThat(result).isEqualTo("[a-b-c]"); + } + + @Test + void shouldConvertObjectArrayToStringWithRange() { + // given: + String[] array = {"a", "b", "c", "d"}; + // when: + String result = ArrayUtils.toString(array, 1, 2, ", ", false, true); + // then: + assertThat(result).isEqualTo("[b, c]"); + } + + // ==================== forEach tests ==================== + + @Test + void shouldApplyForEachToArray() { + // given: + String[] array = {"a", "b", "c"}; + var collected = new ArrayList(); + // when: + ArrayUtils.forEach(array, collected::add); + // then: + assertThat(collected).containsExactly("a", "b", "c"); + } + + @Test + void shouldHandleNullArrayInForEach() { + // given: + var collected = new ArrayList(); + // when: + ArrayUtils.forEach((String[]) null, collected::add); + // then: + assertThat(collected).isEmpty(); + } + + @Test + void shouldApplyForEachWithCondition() { + // given: + Integer[] array = {1, 2, 3, 4, 5}; + var collected = new ArrayList(); + // when: + Predicate condition = n -> n % 2 == 0; + Consumer consumer = collected::add; + ArrayUtils.forEach(array, condition, consumer); + // then: + assertThat(collected).containsExactly(2, 4); + } + + @Test + void shouldApplyForEachWithArgument() { + // given: + String[] array = {"a", "b"}; + var collected = new ArrayList(); + // when: + ArrayUtils.forEach(array, "_suffix", (element, arg) -> collected.add(element + arg)); + // then: + assertThat(collected).containsExactly("a_suffix", "b_suffix"); + } + + @Test + void shouldApplyForEachToDoubleArray() { + // given: + double[] array = {1.0, 2.0, 3.0}; + var collected = new ArrayList(); + // when: + ArrayUtils.forEach(array, collected, (element, list) -> list.add(element)); + // then: + assertThat(collected).containsExactly(1.0, 2.0, 3.0); + } + + @Test + void shouldApplyForEachWithGetter() { + // given: + String[] array = {"hello", "world"}; + var collected = new ArrayList(); + // when: + ArrayUtils.forEach(array, collected, String::length, (len, list) -> list.add(len)); + // then: + assertThat(collected).containsExactly(5, 5); + } + + @Test + void shouldApplyForEachWithConditionAndArgument() { + // given: + Integer[] array = {1, 2, 3, 4, 5}; + var collected = new ArrayList(); + // when: + Predicate condition = n -> n > 2; + BiConsumer consumer = (n, multiplier) -> collected.add(n * multiplier); + ArrayUtils.forEach(array, 10, condition, consumer); + // then: + assertThat(collected).containsExactly(30, 40, 50); + } + + @Test + void shouldApplyForEachWithConditionGetterAndConsumer() { + // given: + String[] array = {"ab", "abc", "abcd"}; + var collected = new ArrayList(); + // when: + ArrayUtils.forEach( + array, + 2, + s -> s.length() > 2, + String::length, + (len, multiplier) -> collected.add(len * multiplier) + ); + // then: + assertThat(collected).containsExactly(6, 8); + } + + @Test + void shouldApplyForEachWithTwoArguments() { + // given: + String[] array = {"a", "b"}; + var collected = new ArrayList(); + // when: + ArrayUtils.forEach(array, "[", "]", (e, prefix, suffix) -> collected.add(prefix + e + suffix)); + // then: + assertThat(collected).containsExactly("[a]", "[b]"); + } + + @Test + void shouldApplyForEachWithGetterAndTwoArguments() { + // given: + String[] array = {"hello", "world"}; + var collected = new ArrayList(); + // when: + ArrayUtils.forEach( + array, + "L=", + "!", + (e, arg1, arg2) -> e.length(), + (len, prefix, suffix) -> collected.add(prefix + len + suffix) + ); + // then: + assertThat(collected).containsExactly("L=5!", "L=5!"); + } + + // ==================== count tests ==================== + + @Test + void shouldCountMatchingElements() { + // given: + Integer[] array = {1, 2, 3, 4, 5, 6}; + // when: + int count = ArrayUtils.count(array, n -> n % 2 == 0); + // then: + assertThat(count).isEqualTo(3); + } + + @Test + void shouldReturnZeroForNullArray() { + // when: + int count = ArrayUtils.count(null, n -> true); + // then: + assertThat(count).isEqualTo(0); + } + + @Test + void shouldReturnZeroForEmptyArray() { + // when: + int count = ArrayUtils.count(new Integer[]{}, n -> true); + // then: + assertThat(count).isEqualTo(0); + } + + // ==================== findAny tests ==================== + + @Test + void shouldFindAnyMatchingElement() { + // given: + String[] array = {"apple", "banana", "cherry"}; + // when: + String result = ArrayUtils.findAny(array, s -> s.startsWith("b")); + // then: + assertThat(result).isEqualTo("banana"); + } + + @Test + void shouldReturnNullWhenNoMatch() { + // given: + String[] array = {"apple", "banana"}; + // when: + String result = ArrayUtils.findAny(array, s -> s.startsWith("z")); + // then: + assertThat(result).isNull(); + } + + @Test + void shouldReturnNullForNullArray() { + // when: + String result = ArrayUtils.findAny((String[]) null, s -> true); + // then: + assertThat(result).isNull(); + } + + @Test + void shouldFindAnyWithArgument() { + // given: + String[] array = {"apple", "banana", "cherry"}; + // when: + String result = ArrayUtils.findAny(array, "an", (s, arg) -> s.contains(arg)); + // then: + assertThat(result).isEqualTo("banana"); + } + + @Test + void shouldFindAnySubElementWithGetter() { + // given: + String[] array = {"ab", "abc", "abcd"}; + // when: + Integer result = ArrayUtils.findAny(array, 3, String::length, (len, target) -> len.equals(target)); + // then: + assertThat(result).isEqualTo(3); + } + + @Test + void shouldFindAnyWithConditionAndGetter() { + // given: + String[] array = {"a", "bb", "ccc", "dddd"}; + // when: + Integer result = ArrayUtils.findAny( + array, + 3, + s -> s.length() > 1, + String::length, + (len, target) -> len >= target + ); + // then: + assertThat(result).isEqualTo(3); + } + + @Test + void shouldFindAnyWithTwoArguments() { + // given: + Integer[] array = {1, 5, 10, 15}; + // when: + Integer result = ArrayUtils.findAny(array, 5, 12, (n, min, max) -> n >= min && n <= max); + // then: + assertThat(result).isEqualTo(5); + } + + // ==================== anyMatch tests ==================== + + @Test + void shouldReturnTrueWhenAnyMatches() { + // given: + String[] array = {"apple", "banana"}; + // when: + boolean result = ArrayUtils.anyMatch(array, s -> s.length() > 5); + // then: + assertThat(result).isTrue(); + } + + @Test + void shouldReturnFalseWhenNoneMatches() { + // given: + String[] array = {"a", "b", "c"}; + // when: + boolean result = ArrayUtils.anyMatch(array, s -> s.length() > 5); + // then: + assertThat(result).isFalse(); + } + + @Test + void shouldReturnFalseForNullArrayInAnyMatch() { + // when: + boolean result = ArrayUtils.anyMatch((String[]) null, s -> true); + // then: + assertThat(result).isFalse(); + } + + @Test + void shouldCheckAnyMatchWithArgument() { + // given: + String[] array = {"hello", "world"}; + // when: + boolean result = ArrayUtils.anyMatch(array, 5, (s, len) -> s.length() == len); + // then: + assertThat(result).isTrue(); + } + + // ==================== map tests ==================== + + @Test + void shouldMapArrayToNewType() { + // given: + String[] source = {"1", "2", "3"}; + // when: + Integer[] result = ArrayUtils.map(source, Integer::parseInt, Integer.class); + // then: + assertThat(result).containsExactly(1, 2, 3); + } + + @Test + void shouldReturnEmptyArrayForEmptySource() { + // given: + String[] source = {}; + // when: + Integer[] result = ArrayUtils.map(source, Integer::parseInt, Integer.class); + // then: + assertThat(result).isEmpty(); + } + + @Test + void shouldMapArrayWithDefault() { + // given: + String[] source = {"a", "b"}; + Integer[] defaultArray = {}; + // when: + Integer[] result = ArrayUtils.map(source, String::length, defaultArray); + // then: + assertThat(result).containsExactly(1, 1); + } + + @Test + void shouldReturnDefaultForNullSource() { + // given: + Integer[] defaultArray = {0}; + // when: + Integer[] result = ArrayUtils.map(null, String::length, defaultArray); + // then: + assertThat(result).containsExactly(0); + } +} diff --git a/rlib-concurrent/src/main/java/javasabr/rlib/concurrent/util/ConcurrentUtils.java b/rlib-concurrent/src/main/java/javasabr/rlib/concurrent/util/ConcurrentUtils.java index 97b231af..06769cbe 100644 --- a/rlib-concurrent/src/main/java/javasabr/rlib/concurrent/util/ConcurrentUtils.java +++ b/rlib-concurrent/src/main/java/javasabr/rlib/concurrent/util/ConcurrentUtils.java @@ -1,8 +1,8 @@ package javasabr.rlib.concurrent.util; import java.util.function.Function; -import javasabr.rlib.common.function.ObjectIntFunction; import javasabr.rlib.concurrent.lock.Lockable; +import javasabr.rlib.functions.ObjIntFunction; import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerManager; import lombok.experimental.UtilityClass; @@ -80,7 +80,7 @@ public static R get(T sync, Function fun } @Nullable - public static R get(T sync, int argument, ObjectIntFunction function) { + public static R get(T sync, int argument, ObjIntFunction function) { sync.lock(); try { return function.apply(sync, argument); diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/BiObjLongConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/BiObjLongConsumer.java new file mode 100644 index 00000000..b7465e37 --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/BiObjLongConsumer.java @@ -0,0 +1,22 @@ +package javasabr.rlib.functions; + +/** + * Represents an operation that accepts two object arguments and a long argument, and returns no result. + * + * @param the type of the first object argument + * @param the type of the second object argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface BiObjLongConsumer { + + /** + * Performs this operation on the given arguments. + * + * @param arg1 the first object argument + * @param arg2 the second object argument + * @param arg3 the long argument + * @since 10.0.0 + */ + void accept(A arg1, B arg2, long arg3); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/BiObjToBoolFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/BiObjToBoolFunction.java new file mode 100644 index 00000000..c1467a67 --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/BiObjToBoolFunction.java @@ -0,0 +1,22 @@ +package javasabr.rlib.functions; + +/** + * Represents a function that accepts two object arguments and produces a boolean result. + * + * @param the type of the first argument + * @param the type of the second argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface BiObjToBoolFunction { + + /** + * Applies this function to the given arguments. + * + * @param arg1 the first argument + * @param arg2 the second argument + * @return true or false based on the evaluation + * @since 10.0.0 + */ + boolean apply(A arg1, B arg2); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/BiObjToBooleanFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/BiObjToBooleanFunction.java deleted file mode 100644 index a64a1a02..00000000 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/BiObjToBooleanFunction.java +++ /dev/null @@ -1,10 +0,0 @@ -package javasabr.rlib.functions; - -/** - * @author JavaSaBr - */ -@FunctionalInterface -public interface BiObjToBooleanFunction { - - boolean apply(A arg1, B arg2); -} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/ByteFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/ByteFunction.java index 768de8c8..9ebbef25 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/ByteFunction.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/ByteFunction.java @@ -1,9 +1,20 @@ package javasabr.rlib.functions; /** - * @author JavaSaBr + * Represents a function that accepts a byte argument and produces a result. + * + * @param the result type + * @since 10.0.0 */ @FunctionalInterface public interface ByteFunction { + + /** + * Applies this function to the given argument. + * + * @param value the byte value + * @return the function result + * @since 10.0.0 + */ R apply(byte value); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/CharSupplier.java b/rlib-functions/src/main/java/javasabr/rlib/functions/CharSupplier.java new file mode 100644 index 00000000..5d7bdc8e --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/CharSupplier.java @@ -0,0 +1,18 @@ +package javasabr.rlib.functions; + +/** + * Represents a supplier of char-valued results. + * + * @since 10.0.0 + */ +@FunctionalInterface +public interface CharSupplier { + + /** + * Gets a result. + * + * @return the char value + * @since 10.0.0 + */ + char getAsChar(); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/DoubleObjConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/DoubleObjConsumer.java new file mode 100644 index 00000000..9fa2fa5c --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/DoubleObjConsumer.java @@ -0,0 +1,20 @@ +package javasabr.rlib.functions; + +/** + * Represents an operation that accepts a double and an object argument, and returns no result. + * + * @param the type of the object argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface DoubleObjConsumer { + + /** + * Performs this operation on the given arguments. + * + * @param arg1 the double argument + * @param arg2 the object argument + * @since 10.0.0 + */ + void accept(double arg1, B arg2); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/FloatBiObjConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/FloatBiObjConsumer.java new file mode 100644 index 00000000..2792572e --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/FloatBiObjConsumer.java @@ -0,0 +1,25 @@ +package javasabr.rlib.functions; + +import org.jspecify.annotations.NullUnmarked; + +/** + * Represents an operation that accepts a float and two object arguments, and returns no result. + * + * @param the type of the first object argument + * @param the type of the second object argument + * @since 10.0.0 + */ +@NullUnmarked +@FunctionalInterface +public interface FloatBiObjConsumer { + + /** + * Performs this operation on the given arguments. + * + * @param arg1 the float argument + * @param arg2 the first object argument + * @param arg3 the second object argument + * @since 10.0.0 + */ + void accept(float arg1, B arg2, C arg3); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/FloatConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/FloatConsumer.java new file mode 100644 index 00000000..1ef41fdd --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/FloatConsumer.java @@ -0,0 +1,18 @@ +package javasabr.rlib.functions; + +/** + * Represents an operation that accepts a single float argument and returns no result. + * + * @since 10.0.0 + */ +@FunctionalInterface +public interface FloatConsumer { + + /** + * Performs this operation on the given float value. + * + * @param arg the float value + * @since 10.0.0 + */ + void consume(float arg); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/FunctionInt.java b/rlib-functions/src/main/java/javasabr/rlib/functions/FunctionInt.java new file mode 100644 index 00000000..05ef898f --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/FunctionInt.java @@ -0,0 +1,20 @@ +package javasabr.rlib.functions; + +/** + * Represents a function that accepts an object and produces an int result. + * + * @param the type of the input argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface FunctionInt { + + /** + * Applies this function to the given argument. + * + * @param arg the function argument + * @return the int result + * @since 10.0.0 + */ + int apply(A arg); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/IntBiObjConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/IntBiObjConsumer.java new file mode 100644 index 00000000..c7b6283c --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/IntBiObjConsumer.java @@ -0,0 +1,22 @@ +package javasabr.rlib.functions; + +/** + * Represents an operation that accepts an int and two object arguments, and returns no result. + * + * @param the type of the first object argument + * @param the type of the second object argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface IntBiObjConsumer { + + /** + * Performs this operation on the given arguments. + * + * @param arg1 the int argument + * @param arg2 the first object argument + * @param arg3 the second object argument + * @since 10.0.0 + */ + void accept(int arg1, B arg2, C arg3); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjConsumer.java index 4030c133..9a93f850 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjConsumer.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjConsumer.java @@ -1,10 +1,20 @@ package javasabr.rlib.functions; /** - * @author JavaSaBr + * Represents an operation that accepts an int and an object argument, and returns no result. + * + * @param the type of the object argument + * @since 10.0.0 */ @FunctionalInterface public interface IntObjConsumer { + /** + * Performs this operation on the given arguments. + * + * @param arg1 the int argument + * @param arg2 the object argument + * @since 10.0.0 + */ void accept(int arg1, B arg2); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjFunction.java index f319226e..2d09f918 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjFunction.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjFunction.java @@ -1,10 +1,22 @@ package javasabr.rlib.functions; /** - * @author JavaSaBr + * Represents a function that accepts an int and an object argument and produces a result. + * + * @param the type of the object argument + * @param the type of the result + * @since 10.0.0 */ @FunctionalInterface public interface IntObjFunction { + /** + * Applies this function to the given arguments. + * + * @param arg1 the int argument + * @param arg2 the object argument + * @return the function result + * @since 10.0.0 + */ R apply(int arg1, B arg2); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjPredicate.java b/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjPredicate.java new file mode 100644 index 00000000..12c24e4a --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/IntObjPredicate.java @@ -0,0 +1,21 @@ +package javasabr.rlib.functions; + +/** + * Represents a predicate that accepts an int and an object argument. + * + * @param the type of the object argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface IntObjPredicate { + + /** + * Evaluates this predicate on the given arguments. + * + * @param arg1 the int argument + * @param arg2 the object argument + * @return true if the arguments match the predicate + * @since 10.0.0 + */ + boolean test(int arg1, B arg2); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/LongBiObjConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/LongBiObjConsumer.java new file mode 100644 index 00000000..c0f24ffa --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/LongBiObjConsumer.java @@ -0,0 +1,22 @@ +package javasabr.rlib.functions; + +/** + * Represents an operation that accepts a long and two object arguments, and returns no result. + * + * @param the type of the first object argument + * @param the type of the second object argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface LongBiObjConsumer { + + /** + * Performs this operation on the given arguments. + * + * @param arg1 the long argument + * @param arg2 the first object argument + * @param arg3 the second object argument + * @since 10.0.0 + */ + void accept(long arg1, B arg2, C arg3); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/LongObjConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/LongObjConsumer.java index 4c9319f0..a56992fc 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/LongObjConsumer.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/LongObjConsumer.java @@ -1,10 +1,20 @@ package javasabr.rlib.functions; /** - * @author JavaSaBr + * Represents an operation that accepts a long and an object argument, and returns no result. + * + * @param the type of the object argument + * @since 10.0.0 */ @FunctionalInterface public interface LongObjConsumer { + /** + * Performs this operation on the given arguments. + * + * @param arg1 the long argument + * @param arg2 the object argument + * @since 10.0.0 + */ void accept(long arg1, B arg2); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/LongObjPredicate.java b/rlib-functions/src/main/java/javasabr/rlib/functions/LongObjPredicate.java new file mode 100644 index 00000000..9d8796cd --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/LongObjPredicate.java @@ -0,0 +1,21 @@ +package javasabr.rlib.functions; + +/** + * Represents a predicate that accepts a long and an object argument. + * + * @param the type of the object argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface LongObjPredicate { + + /** + * Evaluates this predicate on the given arguments. + * + * @param arg1 the long argument + * @param arg2 the object argument + * @return true if the arguments match the predicate + * @since 10.0.0 + */ + boolean test(long arg1, B arg2); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjBoolConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjBoolConsumer.java index 10f58c68..7fe8f76c 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjBoolConsumer.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjBoolConsumer.java @@ -1,10 +1,20 @@ package javasabr.rlib.functions; /** - * @author JavaSaBr + * Represents an operation that accepts an object and a boolean argument, and returns no result. + * + * @param the type of the object argument + * @since 10.0.0 */ @FunctionalInterface public interface ObjBoolConsumer { + /** + * Performs this operation on the given arguments. + * + * @param arg1 the object argument + * @param arg2 the boolean argument + * @since 10.0.0 + */ void accept(A arg1, boolean arg2); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjIntFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjIntFunction.java index 5bd18832..b3597c8a 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjIntFunction.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjIntFunction.java @@ -1,10 +1,22 @@ package javasabr.rlib.functions; /** - * @author JavaSaBr + * Represents a function that accepts an object and an int argument and produces a result. + * + * @param the type of the object argument + * @param the type of the result + * @since 10.0.0 */ @FunctionalInterface public interface ObjIntFunction { + /** + * Applies this function to the given arguments. + * + * @param arg1 the object argument + * @param arg2 the int argument + * @return the function result + * @since 10.0.0 + */ R apply(A arg1, int arg2); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjIntPredicate.java b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjIntPredicate.java index 2b6ba817..a9cf68bd 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjIntPredicate.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjIntPredicate.java @@ -1,10 +1,21 @@ package javasabr.rlib.functions; /** - * @author JavaSaBr + * Represents a predicate that accepts an object and an int argument. + * + * @param the type of the object argument + * @since 10.0.0 */ @FunctionalInterface public interface ObjIntPredicate { + /** + * Evaluates this predicate on the given arguments. + * + * @param arg1 the object argument + * @param arg2 the int argument + * @return true if the arguments match the predicate, false otherwise + * @since 10.0.0 + */ boolean test(A arg1, int arg2); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongFunction.java index 1633f5ea..719fd53c 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongFunction.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongFunction.java @@ -1,10 +1,22 @@ package javasabr.rlib.functions; /** - * @author JavaSaBr + * Represents a function that accepts an object and a long argument and produces a result. + * + * @param the type of the object argument + * @param the type of the result + * @since 10.0.0 */ @FunctionalInterface public interface ObjLongFunction { + /** + * Applies this function to the given arguments. + * + * @param arg1 the object argument + * @param arg2 the long argument + * @return the function result + * @since 10.0.0 + */ R apply(A arg1, long arg2); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongObjConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongObjConsumer.java index 828d56ea..bc8f94f8 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongObjConsumer.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongObjConsumer.java @@ -1,10 +1,22 @@ package javasabr.rlib.functions; +/** + * Represents an operation that accepts an object, a long, and another object argument, and returns no result. + * + * @param the type of the first object argument + * @param the type of the second object argument + * @since 10.0.0 + */ @FunctionalInterface public interface ObjLongObjConsumer { /** * Performs this operation on the given arguments. + * + * @param arg1 the first object argument + * @param arg2 the long argument + * @param arg3 the second object argument + * @since 10.0.0 */ void accept(A arg1, long arg2, C arg3); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongPredicate.java b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongPredicate.java new file mode 100644 index 00000000..f4536d16 --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjLongPredicate.java @@ -0,0 +1,21 @@ +package javasabr.rlib.functions; + +/** + * Represents a predicate that accepts an object and a long argument. + * + * @param the type of the object argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface ObjLongPredicate { + + /** + * Evaluates this predicate on the given arguments. + * + * @param arg1 the object argument + * @param arg2 the long argument + * @return true if the arguments match the predicate + * @since 10.0.0 + */ + boolean test(A arg1, long arg2); +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjObjLongConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjObjLongConsumer.java deleted file mode 100644 index 32387b36..00000000 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjObjLongConsumer.java +++ /dev/null @@ -1,10 +0,0 @@ -package javasabr.rlib.functions; - -@FunctionalInterface -public interface ObjObjLongConsumer { - - /** - * Performs this operation on the given arguments. - */ - void accept(A arg1, B arg2, long arg3); -} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/SafeBiConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeBiConsumer.java new file mode 100644 index 00000000..3ece063f --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeBiConsumer.java @@ -0,0 +1,22 @@ +package javasabr.rlib.functions; + +/** + * Represents an operation that accepts two arguments and may throw an exception. + * + * @param the type of the first argument + * @param the type of the second argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface SafeBiConsumer { + + /** + * Performs this operation on the given arguments. + * + * @param arg1 the first argument + * @param arg2 the second argument + * @throws Exception if an error occurs + * @since 10.0.0 + */ + void accept(A arg1, B arg2) throws Exception; +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/SafeBiFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeBiFunction.java new file mode 100644 index 00000000..1d8aa48f --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeBiFunction.java @@ -0,0 +1,24 @@ +package javasabr.rlib.functions; + +/** + * Represents a function that accepts two arguments and produces a result, and may throw an exception. + * + * @param the type of the first argument + * @param the type of the second argument + * @param the type of the result + * @since 10.0.0 + */ +@FunctionalInterface +public interface SafeBiFunction { + + /** + * Applies this function to the given arguments. + * + * @param arg1 the first argument + * @param arg2 the second argument + * @return the function result + * @throws Exception if an error occurs + * @since 10.0.0 + */ + R apply(A arg1, B arg2) throws Exception; +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/SafeConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeConsumer.java new file mode 100644 index 00000000..6b090868 --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeConsumer.java @@ -0,0 +1,20 @@ +package javasabr.rlib.functions; + +/** + * Represents an operation that accepts a single argument and may throw an exception. + * + * @param the type of the input argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface SafeConsumer { + + /** + * Performs this operation on the given argument. + * + * @param arg the input argument + * @throws Exception if an error occurs + * @since 10.0.0 + */ + void accept(A arg) throws Exception; +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/SafeFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeFunction.java new file mode 100644 index 00000000..f1d1f392 --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeFunction.java @@ -0,0 +1,22 @@ +package javasabr.rlib.functions; + +/** + * Represents a function that accepts one argument and produces a result, and may throw an exception. + * + * @param the type of the input argument + * @param the type of the result + * @since 10.0.0 + */ +@FunctionalInterface +public interface SafeFunction { + + /** + * Applies this function to the given argument. + * + * @param arg the function argument + * @return the function result + * @throws Exception if an error occurs + * @since 10.0.0 + */ + R apply(A arg) throws Exception; +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/SafeRunnable.java b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeRunnable.java new file mode 100644 index 00000000..2730980e --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeRunnable.java @@ -0,0 +1,18 @@ +package javasabr.rlib.functions; + +/** + * Represents a task that may throw an exception. + * + * @since 10.0.0 + */ +@FunctionalInterface +public interface SafeRunnable { + + /** + * Runs this task. + * + * @throws Exception if an error occurs + * @since 10.0.0 + */ + void run() throws Exception; +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/SafeSupplier.java b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeSupplier.java new file mode 100644 index 00000000..21c125a6 --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeSupplier.java @@ -0,0 +1,22 @@ +package javasabr.rlib.functions; + +import org.jspecify.annotations.Nullable; + +/** + * Represents a supplier of results that may throw an exception. + * + * @param the type of the result + * @since 10.0.0 + */ +@FunctionalInterface +public interface SafeSupplier { + + /** + * Gets a result. + * + * @return a result, possibly null + * @throws Exception if an error occurs + * @since 10.0.0 + */ + @Nullable T get() throws Exception; +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/SafeTriFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeTriFunction.java new file mode 100644 index 00000000..8be9c4e8 --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/SafeTriFunction.java @@ -0,0 +1,26 @@ +package javasabr.rlib.functions; + +/** + * Represents a function that accepts three arguments and produces a result, and may throw an exception. + * + * @param the type of the first argument + * @param the type of the second argument + * @param the type of the third argument + * @param the type of the result + * @since 10.0.0 + */ +@FunctionalInterface +public interface SafeTriFunction { + + /** + * Applies this function to the given arguments. + * + * @param arg1 the first argument + * @param arg2 the second argument + * @param arg3 the third argument + * @return the function result + * @throws Exception if an error occurs + * @since 10.0.0 + */ + R apply(F arg1, S arg2, T arg3) throws Exception; +} diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/TriConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/TriConsumer.java index 9bbf4de2..5933439a 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/TriConsumer.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/TriConsumer.java @@ -1,10 +1,23 @@ package javasabr.rlib.functions; +/** + * Represents an operation that accepts three arguments and returns no result. + * + * @param the type of the first argument + * @param the type of the second argument + * @param the type of the third argument + * @since 10.0.0 + */ @FunctionalInterface public interface TriConsumer { /** * Performs this operation on the given arguments. + * + * @param arg1 the first argument + * @param arg2 the second argument + * @param arg3 the third argument + * @since 10.0.0 */ void accept(A arg1, B arg2, C arg3); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/TriFunction.java b/rlib-functions/src/main/java/javasabr/rlib/functions/TriFunction.java index 910d1eb5..83917b6d 100644 --- a/rlib-functions/src/main/java/javasabr/rlib/functions/TriFunction.java +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/TriFunction.java @@ -1,10 +1,25 @@ package javasabr.rlib.functions; /** - * @author JavaSaBr + * Represents a function that accepts three arguments and produces a result. + * + * @param the type of the first argument + * @param the type of the second argument + * @param the type of the third argument + * @param the type of the result + * @since 10.0.0 */ @FunctionalInterface public interface TriFunction { + /** + * Applies this function to the given arguments. + * + * @param arg1 the first argument + * @param arg2 the second argument + * @param arg3 the third argument + * @return the function result + * @since 10.0.0 + */ R apply(A arg1, B arg2, C arg3); } diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/TriPredicate.java b/rlib-functions/src/main/java/javasabr/rlib/functions/TriPredicate.java new file mode 100644 index 00000000..77db2797 --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/TriPredicate.java @@ -0,0 +1,24 @@ +package javasabr.rlib.functions; + +/** + * Represents a predicate that accepts three arguments. + * + * @param the type of the first argument + * @param the type of the second argument + * @param the type of the third argument + * @since 10.0.0 + */ +@FunctionalInterface +public interface TriPredicate { + + /** + * Evaluates this predicate on the given arguments. + * + * @param arg1 the first argument + * @param arg2 the second argument + * @param arg3 the third argument + * @return true if the arguments match the predicate + * @since 10.0.0 + */ + boolean test(A arg1, B arg2, C arg3); +} diff --git a/rlib-io/src/main/java/javasabr/rlib/io/util/FileUtils.java b/rlib-io/src/main/java/javasabr/rlib/io/util/FileUtils.java index b6f41c0f..2c249f9d 100644 --- a/rlib-io/src/main/java/javasabr/rlib/io/util/FileUtils.java +++ b/rlib-io/src/main/java/javasabr/rlib/io/util/FileUtils.java @@ -37,7 +37,10 @@ import org.jspecify.annotations.Nullable; /** - * @author JavaSaBr + * Utility methods for file and path operations including file discovery, extension handling, + * zip extraction, and path manipulation. + * + * @since 10.0.0 */ public class FileUtils { @@ -92,6 +95,13 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO private static final Path[] EMPTY_PATHS = new Path[0]; + /** + * Checks if the filename is a valid Windows filename. + * + * @param filename the filename to validate + * @return true if the filename is valid + * @since 10.0.0 + */ public static boolean isValidFileName(@Nullable String filename) { if (StringUtils.isEmpty(filename)) { @@ -104,7 +114,11 @@ public static boolean isValidFileName(@Nullable String filename) { } /** - * Normalize the file name to an invalid file name. + * Normalizes a filename by replacing invalid characters with underscores. + * + * @param filename the filename to normalize + * @return the normalized filename + * @since 10.0.0 */ public static String normalizeName(@Nullable String filename) { @@ -117,12 +131,27 @@ public static String normalizeName(@Nullable String filename) { .replaceAll("_"); } - - + /** + * Returns all files in the directory matching the specified extensions. + * + * @param directory the directory to search + * @param extensions the file extensions to match, or null for all files + * @return an array of matching paths + * @since 10.0.0 + */ public static Array getFiles(Path directory, String @Nullable ... extensions) { return getFiles(directory, false, extensions); } + /** + * Returns all files in the directory matching the specified extensions. + * + * @param directory the directory to search + * @param includeDirectoriesToResult whether to include directories in the result + * @param extensions the file extensions to match, or null for all files + * @return an array of matching paths + * @since 10.0.0 + */ public static Array getFiles( Path directory, boolean includeDirectoriesToResult, @@ -132,6 +161,14 @@ public static Array getFiles( return Array.copyOf(result); } + /** + * Returns all files from a package matching the specified extensions. + * + * @param pckg the package to search + * @param extensions the file extensions to match, or null for all files + * @return an array of matching paths + * @since 10.0.0 + */ public static Path[] getFiles(Package pckg, String @Nullable ... extensions) { ClassLoader classLoader = Thread @@ -176,6 +213,15 @@ public static Path[] getFiles(Package pckg, String @Nullable ... extensions) { return files.toArray(Path.class); } + /** + * Collects files from a directory into the container. + * + * @param container the container to collect files into + * @param directory the directory to search + * @param includeDirectoriesToResult whether to include directories in the result + * @param extensions the file extensions to match, or null for all files + * @since 10.0.0 + */ public static void collectFilesTo( MutableArray container, Path directory, @@ -210,33 +256,88 @@ public static void collectFilesTo( } } + /** + * Returns the filename of the path as a string. + * + * @param file the path + * @return the filename, or null if the path has no filename + * @since 10.0.0 + */ @Nullable public static String fileName(Path file) { Path fileName = file.getFileName(); return fileName == null ? null : fileName.toString(); } + /** + * Checks if the file has the specified extension. + * + * @param file the file to check + * @param extension the extension to match + * @return true if the file has the extension + * @since 10.0.0 + */ public static boolean hasExtension(Path file, String extension) { String fileName = fileName(file); return fileName != null && fileName.endsWith(extension); } + /** + * Checks if the file has any of the specified extensions. + * + * @param file the file to check + * @param extensions the extensions to match + * @return true if the file has any of the extensions + * @since 10.0.0 + */ public static boolean hasExtensions(Path file, String @Nullable [] extensions) { return hasExtensions(file.toString(), extensions); } + /** + * Checks if the file has any of the specified extensions. + * + * @param file the file to check + * @param extensions the extensions to match + * @return true if the file has any of the extensions + * @since 10.0.0 + */ public static boolean hasExtensions(Path file, @Nullable Array extensions) { return hasExtensions(file.toString(), extensions); } + /** + * Checks if the file has any of the specified extensions. + * + * @param file the file to check + * @param extensions the extensions to match + * @return true if the file has any of the extensions + * @since 10.0.0 + */ public static boolean hasExtensions(Path file, @Nullable Collection extensions) { return hasExtensions(file.toString(), extensions); } + /** + * Checks if the path string ends with any of the specified extensions. + * + * @param path the path string to check + * @param extensions the extensions to match + * @return true if the path ends with any of the extensions + * @since 10.0.0 + */ public static boolean hasExtensions(String path, String @Nullable [] extensions) { - return ArrayUtils.anyMatchR(extensions, path, String::endsWith); + return ArrayUtils.anyMatch(extensions, path, (extension, arg) -> arg.endsWith(extension)); } + /** + * Checks if the path string ends with any of the specified extensions. + * + * @param path the path string to check + * @param extensions the extensions to match + * @return true if the path ends with any of the extensions + * @since 10.0.0 + */ public static boolean hasExtensions(String path, @Nullable Array extensions) { return extensions != null && extensions .iterations() @@ -244,12 +345,27 @@ public static boolean hasExtensions(String path, @Nullable Array extensi .anyMatch(path, String::endsWith); } + /** + * Checks if the path string ends with any of the specified extensions. + * + * @param path the path string to check + * @param extensions the extensions to match + * @return true if the path ends with any of the extensions + * @since 10.0.0 + */ public static boolean hasExtensions(String path, @Nullable Collection extensions) { return extensions != null && extensions .stream() .anyMatch(path::endsWith); } + /** + * Deletes a file or directory recursively. + * + * @param file the file or directory to delete + * @throws UncheckedIOException if an I/O error occurs + * @since 10.0.0 + */ public static void delete(Path file) { try { deleteImpl(file); @@ -266,6 +382,13 @@ private static void deleteImpl(Path path) throws IOException { } } + /** + * Checks if the path has a file extension. + * + * @param path the path to check + * @return true if the path has an extension + * @since 10.0.0 + */ public static boolean hasExtension(@Nullable String path) { if (StringUtils.isEmpty(path)) { @@ -282,13 +405,25 @@ public static boolean hasExtension(@Nullable String path) { } /** - * Get an extension of the path or empty string. + * Returns the extension of the path, or null if none. + * + * @param path the path + * @return the extension without the dot, or null + * @since 10.0.0 */ @Nullable public static String getExtension(@Nullable String path) { return getExtension(path, false); } + /** + * Returns the extension of the path, optionally in lowercase. + * + * @param path the path + * @param toLowerCase whether to convert to lowercase + * @return the extension without the dot, or null + * @since 10.0.0 + */ @Nullable public static String getExtension(@Nullable String path, boolean toLowerCase) { @@ -314,6 +449,13 @@ public static String getExtension(@Nullable String path, boolean toLowerCase) { return result; } + /** + * Returns the extension of the file. + * + * @param file the file + * @return the extension without the dot, or null if directory or no extension + * @since 10.0.0 + */ @Nullable public static String getExtension(Path file) { @@ -324,6 +466,14 @@ public static String getExtension(Path file) { return getExtension(fileName(file)); } + /** + * Returns the extension of the file, optionally in lowercase. + * + * @param file the file + * @param toLowerCase whether to convert to lowercase + * @return the extension without the dot, or null if directory or no extension + * @since 10.0.0 + */ @Nullable public static String getExtension(Path file, boolean toLowerCase) { @@ -334,6 +484,13 @@ public static String getExtension(Path file, boolean toLowerCase) { return getExtension(fileName(file), toLowerCase); } + /** + * Returns the filename without the extension. + * + * @param fileName the filename + * @return the filename without extension, or the original if no extension + * @since 10.0.0 + */ @Nullable public static String getNameWithoutExtension(@Nullable String fileName) { @@ -349,18 +506,37 @@ public static String getNameWithoutExtension(@Nullable String fileName) { return fileName.substring(0, index); } + /** + * Returns the filename without the extension. + * + * @param file the file + * @return the filename without extension, or null if no filename + * @since 10.0.0 + */ @Nullable public static String getNameWithoutExtension(Path file) { return getNameWithoutExtension(fileName(file)); } + /** + * Reads a file from the classpath as a string. + * + * @param path the classpath resource path + * @return the file content as a string, or null if not found + * @since 10.0.0 + */ @Nullable public static String readFromClasspath(String path) { return readFromClasspath(FileUtils.class, path); } /** - * Read the file as a string from classpath. + * Reads a file from the classpath as a string. + * + * @param cs the class to use for loading the resource + * @param path the classpath resource path + * @return the file content as a string, or null if not found + * @since 10.0.0 */ @Nullable public static String readFromClasspath(Class cs, String path) { @@ -372,7 +548,12 @@ public static String readFromClasspath(Class cs, String path) { } /** - * Find a first free file name in the directory. + * Finds the first available filename in the directory, appending a counter if needed. + * + * @param directory the directory to check + * @param file the desired file + * @return the first available filename + * @since 10.0.0 */ public static String getFirstFreeName(Path directory, Path file) { @@ -396,12 +577,14 @@ public static String getFirstFreeName(Path directory, Path file) { } /** - * Unzip the zip file to the destination folder. + * Extracts a zip file to the destination folder. * - * @param destination the destination folder. - * @param zipFile the zip file. - * + * @param destination the destination folder + * @param zipFile the zip file to extract * @return the count of unpacked files + * @throws IllegalArgumentException if the destination folder doesn't exist + * @throws UncheckedIOException if an I/O error occurs + * @since 10.0.0 */ public static int unzip(Path destination, Path zipFile) { if (!Files.exists(destination)) { @@ -434,11 +617,12 @@ public static int unzip(Path destination, Path zipFile) { } /** - * Get a name of the file by the path and the separator. + * Returns the filename from the path using the specified separator. * - * @param path the path. - * @param separator the separator. - * @return the name. + * @param path the path + * @param separator the path separator character + * @return the filename + * @since 10.0.0 */ public static String getName(String path, char separator) { @@ -455,11 +639,12 @@ public static String getName(String path, char separator) { } /** - * Get a parent path of the path using the separator. + * Returns the parent path using the specified separator. * - * @param path the path. - * @param separator the separator. - * @return the parent path. + * @param path the path + * @param separator the path separator character + * @return the parent path + * @since 10.0.0 */ public static String getParent(String path, char separator) { @@ -476,69 +661,84 @@ public static String getParent(String path, char separator) { } /** - * @param directory the directory. - * @param attrs the directory attributes. + * Creates directories, wrapping checked exceptions. + * + * @param directory the directory to create + * @param attrs the directory attributes * @see Files#createDirectories(Path, FileAttribute[]) + * @since 10.0.0 */ public static void createDirectories(Path directory, FileAttribute... attrs) { Utils.unchecked(directory, attrs, Files::createDirectories); } /** - * @param file the file. - * @param options the link options. - * @return the last modified time. + * Returns the last modified time of the file. + * + * @param file the file + * @param options the link options + * @return the last modified time * @see Files#getLastModifiedTime(Path, LinkOption...) + * @since 10.0.0 */ public static FileTime getLastModifiedTime(Path file, LinkOption... options) { return notNull(Utils.uncheckedGet(file, options, Files::getLastModifiedTime)); } /** - * Get a {@link URI} of the file. + * Returns the URI of the file. * - * @param file the file. - * @return the {@link URI}. + * @param file the file + * @return the URI + * @since 10.0.0 */ public static URI getUri(Path file) { return Utils.uncheckedGet(file, Path::toUri); } /** - * Get a {@link URI} of the {@link URL}. + * Returns the URI of the URL. * - * @param url the url. - * @return the {@link URI}. + * @param url the URL + * @return the URI + * @since 10.0.0 */ public static URI getUri(URL url) { return Utils.uncheckedGet(url, URL::toURI); } /** - * Get a {@link URL} of the file. + * Returns the URL of the file. * - * @param file the file. - * @return the {@link URL}. + * @param file the file + * @return the URL + * @since 10.0.0 */ public static URL getUrl(Path file) { return Utils.uncheckedGet(getUri(file), URI::toURL); } /** - * @param base the base file path. - * @param other the other file path. - * @return the resulting relative path, or an empty path if both paths are equal. + * Returns the relative path from base to other. + * + * @param base the base file path + * @param other the other file path + * @return the resulting relative path, or an empty path if both paths are equal * @see Path#relativize(Path) + * @since 10.0.0 */ public static Path relativize(Path base, Path other) { return Utils.uncheckedGet(base, other, Path::relativize); } /** - * @param base the base file path. - * @param other the other filepath. - * @return the resulting relative path, or an empty path if both paths are equal or null. + * Returns the relative path from base to other, or null if either is null. + * + * @param base the base file path + * @param other the other file path + * @return the resulting relative path, or null if either path is null * @see Path#relativize(Path) + * @since 10.0.0 */ public static @Nullable Path safeRelativize(@Nullable Path base, @Nullable Path other) { if (base == null || other == null) { @@ -549,10 +749,12 @@ public static Path relativize(Path base, Path other) { } /** - * Create a new default watch service. + * Creates a new default watch service. * - * @return the new default watch service. + * @return the new default watch service + * @throws UncheckedIOException if an I/O error occurs * @see FileSystems#getDefault() + * @since 10.0.0 */ public static WatchService newDefaultWatchService() { try { @@ -565,10 +767,14 @@ public static WatchService newDefaultWatchService() { } /** - * @param start the start folder. - * @param visitor the visitor. - * @return the start folder. + * Walks a file tree starting from the specified path. + * + * @param start the start folder + * @param visitor the visitor + * @return the start folder + * @throws UncheckedIOException if an I/O error occurs * @see Files#walkFileTree(Path, FileVisitor) + * @since 10.0.0 */ public static Path walkFileTree(Path start, FileVisitor visitor) { try { @@ -579,11 +785,15 @@ public static Path walkFileTree(Path start, FileVisitor visitor) { } /** - * @param prefix the prefix of a temp file. - * @param suffix the suffix of a temp file. - * @param attrs the additional attributes. - * @return the created temp file. + * Creates a temporary file. + * + * @param prefix the prefix of the temp file + * @param suffix the suffix of the temp file + * @param attrs the additional attributes + * @return the created temp file + * @throws UncheckedIOException if an I/O error occurs * @see Files#createTempFile(String, String, FileAttribute[]) + * @since 10.0.0 */ public static Path createTempFile( String prefix, @@ -604,6 +814,15 @@ private static void validateDirectory(Path directory) { } } + /** + * Returns a stream of files in the directory. + * + * @param directory the directory + * @return a stream of paths in the directory + * @throws IllegalArgumentException if the path is not a directory or doesn't exist + * @throws UncheckedIOException if an I/O error occurs + * @since 10.0.0 + */ public static Stream stream(Path directory) { validateDirectory(directory); diff --git a/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java b/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java index a1c5c435..e5aa51aa 100644 --- a/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java +++ b/rlib-io/src/test/java/javasabr/rlib/io/FileUtilsTest.java @@ -1,27 +1,32 @@ package javasabr.rlib.io; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.BasicFileAttributes; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import javasabr.rlib.collections.array.MutableArray; import javasabr.rlib.io.util.FileUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -/** - * @author JavaSaBr - */ -public class FileUtilsTest { +class FileUtilsTest { @Test void shouldGetNameByPath() { + // given: var path = "/some/folder/some/name.ololo"; var path2 = "D:\\some\\folder\\some\\name.ololo"; + // when/then: assertThat(FileUtils.getName(path, '/')) .isEqualTo("name.ololo"); assertThat(FileUtils.getName(path2, '\\')) @@ -30,9 +35,11 @@ void shouldGetNameByPath() { @Test void shouldGetParentByPath() { + // given: var path = "/some/folder/some/name.ololo"; var path2 = "D:\\some\\folder\\some\\name.ololo"; + // when/then: assertThat(FileUtils.getParent(path, '/')) .isEqualTo("/some/folder/some"); assertThat(FileUtils.getParent(path2, '\\')) @@ -41,12 +48,26 @@ void shouldGetParentByPath() { @Test void shouldNormalizeFileName() { - var first = FileUtils.normalizeName("file*:?name!!@#$\"\"wefwef<>.png"); - assertThat(first).isEqualTo("file___name!!@#$__wefwef__.png"); + // given: + var invalidFileName = "file*:?name!!@#$\"\"wefwef<>.png"; + + // when: + var normalized = FileUtils.normalizeName(invalidFileName); + + // then: + assertThat(normalized).isEqualTo("file___name!!@#$__wefwef__.png"); + } + + @Test + void shouldNormalizeEmptyFileName() { + // when/then: + assertThat(FileUtils.normalizeName(null)).isEqualTo("_"); + assertThat(FileUtils.normalizeName("")).isEqualTo("_"); } @Test void shouldGetFileExtension() { + // given: var path1 = "file.txt"; var path2 = "file.tar.gz"; var path3 = "folder/folder.subname/file.png"; @@ -55,6 +76,7 @@ void shouldGetFileExtension() { var path6 = "D:\\folder\\folder.folder\\test"; var path7 = "/folder/folder.folder/test"; + // when/then: assertThat(FileUtils.getExtension(path1)).isEqualTo("txt"); assertThat(FileUtils.getExtension(path2)).isEqualTo("gz"); assertThat(FileUtils.getExtension(path3)).isEqualTo("png"); @@ -67,6 +89,7 @@ void shouldGetFileExtension() { @Test void shouldCheckExistingExtension() { + // given: var path1 = "file.txt"; var path2 = "file.tar.gz"; var path3 = "folder/folder.subname/file.png"; @@ -74,6 +97,7 @@ void shouldCheckExistingExtension() { var path6 = "D:\\folder\\folder.folder\\test"; var path7 = "/folder/folder.folder/test"; + // when/then: assertThat(FileUtils.hasExtension(path1)).isTrue(); assertThat(FileUtils.hasExtension(path2)).isTrue(); assertThat(FileUtils.hasExtension(path3)).isTrue(); @@ -81,9 +105,242 @@ void shouldCheckExistingExtension() { assertThat(FileUtils.hasExtension(path6)).isFalse(); assertThat(FileUtils.hasExtension(path7)).isFalse(); } - + + @Test + void shouldValidateFileName() { + // when/then: - valid filenames + assertThat(FileUtils.isValidFileName("document.txt")).isTrue(); + assertThat(FileUtils.isValidFileName("my-file_123.pdf")).isTrue(); + assertThat(FileUtils.isValidFileName("file")).isTrue(); + + // when/then: - invalid filenames + assertThat(FileUtils.isValidFileName(null)).isFalse(); + assertThat(FileUtils.isValidFileName("")).isFalse(); + assertThat(FileUtils.isValidFileName("file.txt")).isFalse(); + assertThat(FileUtils.isValidFileName("file:name.txt")).isFalse(); + assertThat(FileUtils.isValidFileName("file?name.txt")).isFalse(); + assertThat(FileUtils.isValidFileName("CON")).isFalse(); + assertThat(FileUtils.isValidFileName("PRN")).isFalse(); + assertThat(FileUtils.isValidFileName("NUL")).isFalse(); + assertThat(FileUtils.isValidFileName("COM1")).isFalse(); + assertThat(FileUtils.isValidFileName("LPT1")).isFalse(); + } + + @Test + void shouldGetNameWithoutExtension() { + // when/then: + assertThat(FileUtils.getNameWithoutExtension("file.txt")) + .isEqualTo("file"); + assertThat(FileUtils.getNameWithoutExtension("file.tar.gz")) + .isEqualTo("file.tar"); + assertThat(FileUtils.getNameWithoutExtension("file")) + .isEqualTo("file"); + assertThat(FileUtils.getNameWithoutExtension("")) + .isEqualTo(""); + assertThat(FileUtils.getNameWithoutExtension((String) null)) + .isNull(); + } + + @Test + void shouldGetNameWithoutExtensionFromPath(@TempDir Path tempDir) throws IOException { + // given: + Path fileWithExtension = tempDir.resolve("test.txt"); + Path fileWithoutExtension = tempDir.resolve("testfile"); + Files.createFile(fileWithExtension); + Files.createFile(fileWithoutExtension); + + // when/then: + assertThat(FileUtils.getNameWithoutExtension(fileWithExtension)) + .isEqualTo("test"); + assertThat(FileUtils.getNameWithoutExtension(fileWithoutExtension)) + .isEqualTo("testfile"); + } + @Test - void shouldUnzipFileCorrectly() throws IOException { + void shouldGetFileName(@TempDir Path tempDir) throws IOException { + // given: + Path file = tempDir.resolve("myfile.txt"); + Files.createFile(file); + + // when: + String fileName = FileUtils.fileName(file); + + // then: + assertThat(fileName).isEqualTo("myfile.txt"); + } + + @Test + void shouldCheckExtensionOnPath(@TempDir Path tempDir) throws IOException { + // given: + Path txtFile = tempDir.resolve("document.txt"); + Path pngFile = tempDir.resolve("image.png"); + Files.createFile(txtFile); + Files.createFile(pngFile); + + // when/then: + assertThat(FileUtils.hasExtension(txtFile, ".txt")).isTrue(); + assertThat(FileUtils.hasExtension(txtFile, ".pdf")).isFalse(); + assertThat(FileUtils.hasExtension(pngFile, ".png")).isTrue(); + } + + @Test + void shouldDeleteFile(@TempDir Path tempDir) throws IOException { + // given: + Path fileToDelete = tempDir.resolve("to-delete.txt"); + Files.writeString(fileToDelete, "content"); + assertThat(fileToDelete).exists(); + + // when: + FileUtils.delete(fileToDelete); + + // then: + assertThat(fileToDelete).doesNotExist(); + } + + @Test + void shouldDeleteDirectoryRecursively(@TempDir Path tempDir) throws IOException { + // given: + Path dirToDelete = tempDir.resolve("dir-to-delete"); + Files.createDirectories(dirToDelete); + Files.writeString(dirToDelete.resolve("file1.txt"), "content1"); + Files.writeString(dirToDelete.resolve("file2.txt"), "content2"); + + Path subDir = dirToDelete.resolve("subdir"); + Files.createDirectories(subDir); + Files.writeString(subDir.resolve("file3.txt"), "content3"); + + assertThat(dirToDelete).exists(); + + // when: + FileUtils.delete(dirToDelete); + + // then: + assertThat(dirToDelete).doesNotExist(); + } + + @Test + void shouldGetFilesFromDirectory(@TempDir Path tempDir) throws IOException { + // given: + Files.writeString(tempDir.resolve("file1.txt"), "content1"); + Files.writeString(tempDir.resolve("file2.txt"), "content2"); + Files.writeString(tempDir.resolve("file3.png"), "content3"); + + // when: + var allFiles = FileUtils.getFiles(tempDir); + var txtFiles = FileUtils.getFiles(tempDir, ".txt"); + + // then: + assertThat(allFiles).hasSize(3); + assertThat(txtFiles).hasSize(2); + } + + @Test + void shouldCreateDirectories(@TempDir Path tempDir) { + // given: + Path nestedDir = tempDir + .resolve("level1") + .resolve("level2") + .resolve("level3"); + assertThat(nestedDir).doesNotExist(); + + // when: + FileUtils.createDirectories(nestedDir); + + // then: + assertThat(nestedDir).exists().isDirectory(); + } + + @Test + void shouldStreamDirectory(@TempDir Path tempDir) throws IOException { + // given: + Files.writeString(tempDir.resolve("file1.txt"), "content1"); + Files.writeString(tempDir.resolve("file2.txt"), "content2"); + Path subDir = tempDir.resolve("subdir"); + Files.createDirectories(subDir); + + // when: + var files = FileUtils + .stream(tempDir) + .toList(); + + // then: + assertThat(files).hasSize(3); + } + + @Test + void shouldThrowWhenStreamingNonDirectory(@TempDir Path tempDir) throws IOException { + // given: + Path file = tempDir.resolve("file.txt"); + Files.writeString(file, "content"); + + // when/then: + assertThatThrownBy(() -> FileUtils.stream(file)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void shouldGetExtensionFromPath(@TempDir Path tempDir) throws IOException { + // given: + Path txtFile = tempDir.resolve("document.txt"); + Path directory = tempDir.resolve("subdir"); + Files.createFile(txtFile); + Files.createDirectories(directory); + + // when/then: + assertThat(FileUtils.getExtension(txtFile)) + .isEqualTo("txt"); + assertThat(FileUtils.getExtension(txtFile, true)) + .isEqualTo("txt"); + assertThat(FileUtils.getExtension(directory)) + .isNull(); + } + + @Test + void shouldGetUri(@TempDir Path tempDir) throws IOException { + // given: + Path file = tempDir.resolve("test.txt"); + Files.createFile(file); + + // when: + var uri = FileUtils.getUri(file); + + // then: + assertThat(uri).isNotNull(); + assertThat(uri.toString()).contains("test.txt"); + } + + @Test + void shouldRelativizePaths(@TempDir Path tempDir) throws IOException { + // given: + Path base = tempDir.resolve("base"); + Path other = tempDir + .resolve("base") + .resolve("sub") + .resolve("file.txt"); + Files.createDirectories(other.getParent()); + Files.createFile(other); + + String expected = "sub/file.txt".replace("/", tempDir + .getFileSystem() + .getSeparator()); + + // when: + Path relative = FileUtils.relativize(base, other); + + // then: + assertThat(relative.toString()).isEqualTo(expected); + } + + @Test + void shouldSafeRelativizeWithNulls() { + // when/then: + assertThat(FileUtils.safeRelativize(null, Path.of("/some/path"))).isNull(); + assertThat(FileUtils.safeRelativize(Path.of("/base"), null)).isNull(); + assertThat(FileUtils.safeRelativize(null, null)).isNull(); + } + + @Test + void shouldUnzipFileCorrectly(@TempDir Path tempDir) throws IOException { // given: Path zipFile = Files.createTempFile("test-archive", ".zip"); @@ -110,31 +367,240 @@ void shouldUnzipFileCorrectly() throws IOException { zout.write("test text 5".getBytes(StandardCharsets.UTF_8)); } - Path tempDirectory = Files.createTempDirectory("test-unzip"); - Path outputDir = tempDirectory + Path outputDir = tempDir .resolve("output") .resolve("folder"); - + Files.createDirectories(outputDir); - + // when: int unpackedFiles = FileUtils.unzip(outputDir, zipFile); // then: assertThat(unpackedFiles).isEqualTo(3); - assertThat(outputDir - .resolve("fileA.txt")) - .exists(); - assertThat(outputDir - .resolve("dir_a") - .resolve("fileC.txt")) - .exists(); - assertThat(tempDirectory - .resolve("output") - .resolve("fileB.txt")) - .doesNotExist(); - assertThat(tempDirectory - .resolve("fileE.txt")) - .doesNotExist(); + assertThat(outputDir.resolve("fileA.txt")).exists(); + assertThat(outputDir.resolve("dir_a").resolve("fileC.txt")).exists(); + assertThat(tempDir.resolve("output").resolve("fileB.txt")).doesNotExist(); + assertThat(tempDir.resolve("fileE.txt")).doesNotExist(); + + // cleanup: + FileUtils.delete(zipFile); + } + + @Test + void shouldThrowWhenUnzipToNonExistentDirectory(@TempDir Path tempDir) throws IOException { + // given: + Path zipFile = Files.createTempFile("test-archive", ".zip"); + try (var zout = new ZipOutputStream(Files.newOutputStream(zipFile, StandardOpenOption.CREATE))) { + zout.putNextEntry(new ZipEntry("file.txt")); + zout.write("content".getBytes(StandardCharsets.UTF_8)); + } + Path nonExistentDir = tempDir.resolve("/non/existent/directory"); + + // when/then: + assertThatThrownBy(() -> FileUtils.unzip(nonExistentDir, zipFile)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void shouldCheckMultipleExtensionsOnPath(@TempDir Path tempDir) throws IOException { + // given: + Path txtFile = tempDir.resolve("document.txt"); + Path pngFile = tempDir.resolve("image.png"); + Path jpgFile = tempDir.resolve("photo.jpg"); + Files.createFile(txtFile); + Files.createFile(pngFile); + Files.createFile(jpgFile); + + String[] imageExtensions = {".png", ".jpg", ".gif"}; + String[] textExtensions = {".txt", ".md", ".doc"}; + + // when/then: + assertThat(FileUtils.hasExtensions(txtFile, textExtensions)).isTrue(); + assertThat(FileUtils.hasExtensions(txtFile, imageExtensions)).isFalse(); + assertThat(FileUtils.hasExtensions(pngFile, imageExtensions)).isTrue(); + assertThat(FileUtils.hasExtensions(jpgFile, imageExtensions)).isTrue(); + } + + @Test + void shouldCheckMultipleExtensionsOnString() { + // given: + var txtPath = "document.txt"; + var pngPath = "image.png"; + var noExtPath = "noextension"; + + String[] imageExtensions = {".png", ".jpg", ".gif"}; + String[] textExtensions = {".txt", ".md", ".doc"}; + + // when/then: + assertThat(FileUtils.hasExtensions(txtPath, textExtensions)).isTrue(); + assertThat(FileUtils.hasExtensions(txtPath, imageExtensions)).isFalse(); + assertThat(FileUtils.hasExtensions(pngPath, imageExtensions)).isTrue(); + assertThat(FileUtils.hasExtensions(noExtPath, textExtensions)).isFalse(); + assertThat(FileUtils.hasExtensions(txtPath, (String[]) null)).isFalse(); + } + + @Test + void shouldGetFirstFreeName(@TempDir Path tempDir) throws IOException { + // given: + Path existingFile = tempDir.resolve("file.txt"); + Files.createFile(existingFile); + + // when: + String firstName = FileUtils.getFirstFreeName(tempDir, existingFile); + + // then: + assertThat(firstName).isEqualTo("file_1.txt"); + + // given: - create file_1.txt + Files.createFile(tempDir.resolve("file_1.txt")); + + // when: + String secondName = FileUtils.getFirstFreeName(tempDir, existingFile); + + // then: + assertThat(secondName).isEqualTo("file_2.txt"); + } + + @Test + void shouldGetFirstFreeNameWhenNotExists(@TempDir Path tempDir) { + // given: + Path nonExistingFile = tempDir.resolve("newfile.txt"); + + // when: + String name = FileUtils.getFirstFreeName(tempDir, nonExistingFile); + + // then: + assertThat(name).isEqualTo("newfile.txt"); + } + + @Test + void shouldCreateTempFile() throws IOException { + // when: + Path tempFile = FileUtils.createTempFile("test-prefix", ".tmp"); + + // then: + assertThat(tempFile).exists(); + assertThat(tempFile.getFileName().toString()).startsWith("test-prefix"); + assertThat(tempFile.getFileName().toString()).endsWith(".tmp"); + + // cleanup + Files.deleteIfExists(tempFile); + } + + @Test + void shouldGetUrl(@TempDir Path tempDir) throws IOException { + // given: + Path file = tempDir.resolve("test.txt"); + Files.createFile(file); + + // when: + var url = FileUtils.getUrl(file); + + // then: + assertThat(url).isNotNull(); + assertThat(url.toString()).contains("test.txt"); + } + + @Test + void shouldGetLastModifiedTime(@TempDir Path tempDir) throws IOException { + // given: + Path file = tempDir.resolve("test.txt"); + Files.writeString(file, "content"); + + // when: + var lastModified = FileUtils.getLastModifiedTime(file); + + // then: + assertThat(lastModified).isNotNull(); + assertThat(lastModified.toMillis()).isGreaterThan(0); + } + + @Test + void shouldGetFilesWithDirectoriesIncluded(@TempDir Path tempDir) throws IOException { + // given: + Path testDir = tempDir.resolve("testdir"); + Files.createDirectories(testDir); + Files.writeString(testDir.resolve("file1.txt"), "content1"); + Files.writeString(testDir.resolve("file2.txt"), "content2"); + Path subDir = testDir.resolve("subdir"); + Files.createDirectories(subDir); + + // when: + var filesWithDirs = FileUtils.getFiles(testDir, true, (String[]) null); + var filesWithoutDirs = FileUtils.getFiles(testDir, false, (String[]) null); + + // then: + // With dirs: testDir + subdir + file1.txt + file2.txt = 4 + assertThat(filesWithDirs).hasSize(4); + // Without dirs: file1.txt + file2.txt = 2 + assertThat(filesWithoutDirs).hasSize(2); + } + + @Test + void shouldWalkFileTree(@TempDir Path tempDir) throws IOException { + // given: + Files.writeString(tempDir.resolve("file1.txt"), "content1"); + Path subDir = tempDir.resolve("subdir"); + Files.createDirectories(subDir); + Files.writeString(subDir.resolve("file2.txt"), "content2"); + + var visitedFiles = MutableArray.ofType(Path.class); + + // when: + FileUtils.walkFileTree(tempDir, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + visitedFiles.add(file); + return FileVisitResult.CONTINUE; + } + }); + + // then: + assertThat(visitedFiles).hasSize(2); + } + + @Test + void shouldReturnNullFileNameForRootPath() { + // given: + Path rootPath = Path.of("/"); + + // when: + String fileName = FileUtils.fileName(rootPath); + + // then: + assertThat(fileName).isNull(); + } + + @Test + void shouldHandleShortPathsInGetName() { + // when/then: + assertThat(FileUtils.getName("a", '/')) + .isEqualTo("a"); + assertThat(FileUtils.getName("", '/')) + .isEqualTo(""); + } + + @Test + void shouldHandleShortPathsInGetParent() { + // when/then: + assertThat(FileUtils.getParent("a", '/')) + .isEqualTo("a"); + assertThat(FileUtils.getParent("", '/')) + .isEqualTo(""); + } + + @Test + void shouldHandlePathWithNoSeparatorInGetName() { + // when/then: + assertThat(FileUtils.getName("filename.txt", '/')) + .isEqualTo("filename.txt"); + } + + @Test + void shouldHandlePathWithNoSeparatorInGetParent() { + // when/then: + assertThat(FileUtils.getParent("filename.txt", '/')) + .isEqualTo("filename.txt"); } } diff --git a/rlib-reusable/src/main/java/javasabr/rlib/reusable/BoundReusable.java b/rlib-reusable/src/main/java/javasabr/rlib/reusable/BoundReusable.java index fa7ee5c4..1a9b155d 100644 --- a/rlib-reusable/src/main/java/javasabr/rlib/reusable/BoundReusable.java +++ b/rlib-reusable/src/main/java/javasabr/rlib/reusable/BoundReusable.java @@ -1,6 +1,16 @@ package javasabr.rlib.reusable; +/** + * A reusable object that is bound to a pool and can be released back to it. + * + * @since 10.0.0 + */ public interface BoundReusable extends Reusable { + /** + * Releases this object back to its pool. + * + * @since 10.0.0 + */ void release(); } diff --git a/rlib-reusable/src/main/java/javasabr/rlib/reusable/Reusable.java b/rlib-reusable/src/main/java/javasabr/rlib/reusable/Reusable.java index b953519e..87908264 100644 --- a/rlib-reusable/src/main/java/javasabr/rlib/reusable/Reusable.java +++ b/rlib-reusable/src/main/java/javasabr/rlib/reusable/Reusable.java @@ -1,12 +1,16 @@ package javasabr.rlib.reusable; /** - * @author JavaSaBr + * Represents a reusable object that can be cleaned up and reused. + * + * @since 10.0.0 */ public interface Reusable extends AutoCloseable { /** - * Cleanup this object + * Cleans up this object for reuse. + * + * @since 10.0.0 */ default void cleanup() {} diff --git a/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/Pool.java b/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/Pool.java index 1c4c9c57..0e9bf3c2 100644 --- a/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/Pool.java +++ b/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/Pool.java @@ -8,30 +8,79 @@ import org.jspecify.annotations.Nullable; /** - * @author JavaSaBr + * A pool for storing and reusing objects. + * + * @param the element type + * @since 10.0.0 */ public interface Pool { + /** + * Puts an object back into the pool. + * + * @param object the object to put + * @since 10.0.0 + */ void put(E object); + /** + * Takes an object from the pool if available. + * + * @return the object, or null if the pool is empty + * @since 10.0.0 + */ @Nullable E take(); + /** + * Takes an object from the pool, or creates one using the factory if empty. + * + * @param factory the factory to create a new object + * @return the pooled or newly created object + * @since 10.0.0 + */ default E take(Supplier factory) { E take = take(); return take != null ? take : factory.get(); } + /** + * Takes an object from the pool, or creates one using the factory if empty. + * + * @param the factory argument type + * @param arg1 the factory argument + * @param factory the factory to create a new object + * @return the pooled or newly created object + * @since 10.0.0 + */ default E take(T arg1, Function factory) { E take = take(); return take != null ? take : factory.apply(arg1); } + /** + * Takes an object from the pool, or creates one using the factory if empty. + * + * @param arg1 the factory argument + * @param factory the factory to create a new object + * @return the pooled or newly created object + * @since 10.0.0 + */ default E take(long arg1, LongFunction factory) { E take = take(); return take != null ? take : factory.apply(arg1); } + /** + * Takes an object from the pool, or creates one using the factory if empty. + * + * @param the first factory argument type + * @param arg1 the first factory argument + * @param arg2 the second factory argument + * @param factory the factory to create a new object + * @return the pooled or newly created object + * @since 10.0.0 + */ default E take( F arg1, long arg2, @@ -40,6 +89,17 @@ default E take( return take != null ? take : factory.apply(arg1, arg2); } + /** + * Takes an object from the pool, or creates one using the factory if empty. + * + * @param the first factory argument type + * @param the second factory argument type + * @param arg1 the first factory argument + * @param arg2 the second factory argument + * @param factory the factory to create a new object + * @return the pooled or newly created object + * @since 10.0.0 + */ default E take( F arg1, S arg2, diff --git a/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/PoolFactory.java b/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/PoolFactory.java index 3ca59c25..2853f9d8 100644 --- a/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/PoolFactory.java +++ b/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/PoolFactory.java @@ -5,16 +5,45 @@ import javasabr.rlib.reusable.pool.impl.ArrayBasedReusablePool; import javasabr.rlib.reusable.pool.impl.LockableArrayBasePool; +/** + * Factory for creating pool instances. + * + * @since 10.0.0 + */ public class PoolFactory { + /** + * Creates a new array-based pool. + * + * @param the element type + * @param type the element class + * @return the new pool + * @since 10.0.0 + */ public static Pool newPool(Class type) { return new ArrayBasedPool<>(type); } + /** + * Creates a new array-based pool for reusable objects. + * + * @param the reusable element type + * @param type the element class + * @return the new reusable pool + * @since 10.0.0 + */ public static ReusablePool newReusablePool(Class type) { return new ArrayBasedReusablePool<>(type); } + /** + * Creates a new lock-based pool for thread-safe access. + * + * @param the element type + * @param type the element class + * @return the new lock-based pool + * @since 10.0.0 + */ public static Pool newLockBasePool(Class type) { return new LockableArrayBasePool<>(type); } diff --git a/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/ReusablePool.java b/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/ReusablePool.java index 13986e29..46f18f9e 100644 --- a/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/ReusablePool.java +++ b/rlib-reusable/src/main/java/javasabr/rlib/reusable/pool/ReusablePool.java @@ -3,6 +3,9 @@ import javasabr.rlib.reusable.Reusable; /** - * @author JavaSaBr + * A pool specifically for {@link Reusable} objects. + * + * @param the reusable element type + * @since 10.0.0 */ public interface ReusablePool extends Pool {}