Skip to content

Commit

Permalink
v0.0.9
Browse files Browse the repository at this point in the history
String utils extension
Optional utils extension
Collection utils extension
Date utils extension
  • Loading branch information
HijackerMax committed Sep 18, 2023
1 parent 95a6666 commit d6d6e48
Show file tree
Hide file tree
Showing 11 changed files with 515 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,6 @@ Just add this to your **pom.xml**
<dependency>
<groupId>com.hijackermax</groupId>
<artifactId>utils</artifactId>
<version>0.0.8</version>
<version>0.0.9</version>
</dependency>
```
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.hijackermax</groupId>
<artifactId>utils</artifactId>
<version>0.0.8</version>
<version>0.0.9</version>

<name>utils</name>
<description>A set of utils that can help in app development</description>
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/com/hijackermax/utils/lang/CollectionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -789,4 +789,43 @@ public static boolean isEmpty(Enumeration<?> value) {
public static <T> Stream<T> safeStreamOf(Enumeration<T> input) {
return isEmpty(input) ? Stream.empty() : EnumerationSpliterator.ofOrdered(input).stream();
}

/**
* Checks if any of input {@link Collection} elements satisfies provided {@link Predicate}
*
* @param values collection that should be checked
* @param valuesPredicate the predicate that should be applied to source elements collection
* @param <T> collection elements type
* @return true if collection contains at least one element that satisfies provided predicate
* @since 0.0.9
*/
public static <T> boolean safeAnyMatch(Collection<? extends T> values, Predicate<? super T> valuesPredicate) {
return safeStreamOf(values).anyMatch(valuesPredicate);
}

/**
* Checks if all of input {@link Collection} elements satisfy provided {@link Predicate}
*
* @param values collection that should be checked
* @param valuesPredicate the predicate that should be applied to source elements collection
* @param <T> collection elements type
* @return true if collection contains all elements that satisfy provided predicate
* @since 0.0.9
*/
public static <T> boolean safeAllMatch(Collection<? extends T> values, Predicate<? super T> valuesPredicate) {
return isNotEmpty(values) && values.stream().allMatch(valuesPredicate);
}

/**
* Checks if none of input {@link Collection} elements satisfy provided {@link Predicate}
*
* @param values collection that should be checked
* @param valuesPredicate the predicate that should be applied to source elements collection
* @param <T> collection elements type
* @return true if collection contains no elements that satisfy provided predicate
* @since 0.0.9
*/
public static <T> boolean safeNoneMatch(Collection<? extends T> values, Predicate<? super T> valuesPredicate) {
return isEmpty(values) || values.stream().noneMatch(valuesPredicate);
}
}
102 changes: 102 additions & 0 deletions src/main/java/com/hijackermax/utils/lang/DateUtils.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.hijackermax.utils.lang;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.chrono.ChronoLocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Objects;
Expand Down Expand Up @@ -186,6 +188,106 @@ public static boolean inRange(Date value, Date target, long offsetMs) {
return between(value, shiftDateByMs(target, -offsetMs), shiftDateByMs(target, offsetMs));
}

/**
* Checks if provided {@link ChronoLocalDate} value is before {@link ChronoLocalDate} point in time
*
* @param value the value that should be checked
* @param pointInTime some date that value should be compared to
* @return true if both dates are not null and provided value is before provided point of time, otherwise false
* @since 0.0.9
*/
public static boolean safeBefore(ChronoLocalDate value, ChronoLocalDate pointInTime) {
return Objects.nonNull(value) && Objects.nonNull(pointInTime) && value.isBefore(pointInTime);
}

/**
* Checks if provided {@link ChronoLocalDate} value is after {@link ChronoLocalDate} point in time
*
* @param value the value that should be checked
* @param pointInTime some date that value should be compared to
* @return true if both dates are not null and provided value is after provided point of time, otherwise false
* @since 0.0.9
*/
public static boolean safeAfter(ChronoLocalDate value, ChronoLocalDate pointInTime) {
return Objects.nonNull(value) && Objects.nonNull(pointInTime) && value.isAfter(pointInTime);
}

/**
* Checks if provided {@link ChronoLocalDate} value is after or the same as {@link ChronoLocalDate} point in time
*
* @param value the value that should be checked
* @param pointInTime some date that value should be compared to
* @return true if both dates are not null and provided value is after or equal to provided point of time, otherwise false
* @since 0.0.9
*/
public static boolean safeAfterOrSame(ChronoLocalDate value, ChronoLocalDate pointInTime) {
return Objects.nonNull(value) && Objects.nonNull(pointInTime) && !value.isBefore(pointInTime);
}

/**
* Checks if provided {@link ChronoLocalDate} value is before or the same as {@link ChronoLocalDate} point in time
*
* @param value the value that should be checked
* @param pointInTime some date that value should be compared to
* @return true if both dates are not null and provided value is before or equal to provided point of time, otherwise false
* @since 0.0.9
*/
public static boolean safeBeforeOrSame(ChronoLocalDate value, ChronoLocalDate pointInTime) {
return Objects.nonNull(value) && Objects.nonNull(pointInTime) && !value.isAfter(pointInTime);
}

/**
* Provides null-safe check if provided value {@link ChronoLocalDate} between two provided boundary {@link ChronoLocalDate} or equal to one of them
*
* @param value date that should be checked
* @param leftBound start boundary date
* @param rightBound end boundary date
* @return true if date between provided boundaries, false if not or one of the provided dates is null
* @since 0.0.9
*/
public static boolean between(ChronoLocalDate value, ChronoLocalDate leftBound, ChronoLocalDate rightBound) {
if (Objects.isNull(value) || Objects.isNull(leftBound) || Objects.isNull(rightBound)) {
return false;
}
return !leftBound.isAfter(value) && !rightBound.isBefore(value);
}

/**
* Shifts provided {@link LocalDate} with provided amount of days
*
* @param source source date
* @param shiftValue amount of days that should be used to shift source date
* @return shifted date, or null if source is null
* @since 0.0.9
*/
public static LocalDate shiftDateByDays(LocalDate source, long shiftValue) {
return Objects.isNull(source) ? null : source.plusDays(shiftValue);
}

/**
* Shifts provided {@link LocalDate} with provided amount of months
*
* @param source source date
* @param shiftValue amount of months that should be used to shift source date
* @return shifted date, or null if source is null
* @since 0.0.9
*/
public static LocalDate shiftDateByMonths(LocalDate source, long shiftValue) {
return Objects.isNull(source) ? null : source.plusMonths(shiftValue);
}

/**
* Shifts provided {@link LocalDate} with provided amount of years
*
* @param source source date
* @param shiftValue amount of years that should be used to shift source date
* @return shifted date, or null if source is null
* @since 0.0.9
*/
public static LocalDate shiftDateByYears(LocalDate source, long shiftValue) {
return Objects.isNull(source) ? null : source.plusYears(shiftValue);
}

private static ZonedDateTime getZonedDateTime(Date source) {
return ZonedDateTime.ofInstant(source.toInstant(), ZoneOffset.UTC);
}
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/hijackermax/utils/lang/FunctionalUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,16 @@ public static <T, U> Predicate<T> mappedPredicate(Function<T, U> transformer, Pr
return source -> Objects.nonNull(source) &&
Objects.requireNonNull(transformer).andThen(Objects.requireNonNull(extractedPredicate)::test).apply(source);
}

/**
* Provides empty value {@link Consumer}
*
* @param <T> supplied value type
* @return empty value consumer
* @since 0.0.9
*/
public static <T> Consumer<T> emptyConsumer() {
return v -> {
};
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/hijackermax/utils/lang/OptionalUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.Optional.empty;
import static java.util.Optional.ofNullable;

/**
* Useful optional providers
Expand Down Expand Up @@ -99,4 +102,19 @@ public static Optional<String> ofBlank(String value) {
public static <T, C extends Collection<T>> Optional<C> ofEmptyCollection(C value) {
return CollectionUtils.isEmpty(value) ? Optional.empty() : Optional.of(value);
}

/**
* Returns an {@link Optional} describing the given pattern matcher against provided {@link CharSequence}
*
* @param pattern a compiled representation of a regular expression
* @param value a character sequence to be matched
* @return an {@link Optional} with a matcher as value if a subsequence of the input sequence matches the input pattern,
* otherwise an empty {@link Optional}
* @since 0.0.9
*/
public static Optional<Matcher> ofFind(Pattern pattern, CharSequence value) {
return Objects.isNull(value) ? Optional.empty() : ofNullable(pattern)
.map(p -> p.matcher(value))
.filter(Matcher::find);
}
}
131 changes: 130 additions & 1 deletion src/main/java/com/hijackermax/utils/lang/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.hijackermax.utils.lang.CollectionUtils.safeStreamOf;
import static com.hijackermax.utils.lang.NumberUtils.requireGreaterThanZero;

/**
Expand Down Expand Up @@ -205,7 +210,7 @@ public static <T> Function<Collection<T>, String> join(String delimiter, Functio
public static <T> String join(Collection<? extends T> collection,
String delimiter,
Function<? super T, String> toStringConverter) {
return CollectionUtils.safeStreamOf(collection)
return safeStreamOf(collection)
.filter(Objects::nonNull)
.map(toStringConverter)
.map(StringUtils::trimToEmpty)
Expand Down Expand Up @@ -488,4 +493,128 @@ public static Predicate<String> contains(String fragment) {
public static Predicate<String> hasLength(ComparisonOperators operator, int reference) {
return source -> isNotEmpty(source) && NumberUtils.compare(source.length(), requireGreaterThanZero(reference), operator);
}

/**
* Passes provided {@link String} if not empty to the provided string {@link Consumer}
*
* @param value the value to check
* @param valueConsumer non-empty value consumer
* @since 0.0.9
*/
public static void ifNotEmpty(String value, Consumer<String> valueConsumer) {
if (isNotEmpty(value)) {
valueConsumer.accept(value);
}
}

/**
* Passes provided {@link String} if not blank to the provided string {@link Consumer}
*
* @param value the value to check
* @param valueConsumer non-blank value consumer
* @since 0.0.9
*/
public static void ifNotBlank(String value, Consumer<String> valueConsumer) {
if (isNotBlank(value)) {
valueConsumer.accept(value);
}
}

/**
* Returns capitalized variant of provided {@link String} with space as default word delimiter
*
* @param source the value to capitalize
* @return capitalized string or empty string if null or blank string is provided
* @since 0.0.9
*/
public static String capitalize(String source) {
return capitalize(source, ' ');
}

/**
* Returns capitalized variant of provided {@link String} with provided words delimiters
*
* @param source the value to capitalize
* @param delimiters the words delimiters
* @return capitalized string or empty string if null or blank string is provided or source string if no delimiters provided
* @since 0.0.9
*/
public static String capitalize(String source, char... delimiters) {
if (isBlank(source)) {
return EMPTY;
}
if (Objects.isNull(delimiters) || 0 == delimiters.length) {
return source;
}

Set<Integer> delimiterValues = IntStream.range(0, delimiters.length)
.mapToObj(idx -> Character.codePointAt(delimiters, idx))
.collect(Collectors.toSet());

String lowerCaseSource = source.trim().toLowerCase();
int sourceLength = lowerCaseSource.length();
int[] resultValues = new int[sourceLength];
int resultEndIdx = 0;
boolean capitalizeNext = false;
for (int idx = 0; idx < sourceLength; ) {
int charAt = lowerCaseSource.codePointAt(idx);
if (delimiterValues.contains(charAt)) {
capitalizeNext = true;
idx += Character.charCount(charAt);
resultValues[resultEndIdx++] = charAt;
continue;
}
if (capitalizeNext || 0 == idx) {
int newValue = Character.toTitleCase(charAt);
idx += Character.charCount(newValue);
resultValues[resultEndIdx++] = newValue;
capitalizeNext = false;
continue;
}
idx += Character.charCount(charAt);
resultValues[resultEndIdx++] = charAt;
}
return new String(resultValues, 0, resultEndIdx);
}

/**
* Joins provided {@link Collection} of {@link CharSequence} with provided delimiter
*
* @param elements collection of charSequences to join
* @param delimiter the delimiter
* @return joint {@link String} or empty string if provided collection is empty or null
* @since 0.0.9
*/
public static String safeJoin(Collection<? extends CharSequence> elements, CharSequence delimiter) {
return CollectionUtils.safeStreamOf(elements)
.collect(Collectors.joining(delimiter));
}

/**
* Passes provided {@link String} pair if both of them not empty to the provided string {@link BiConsumer}
*
* @param left the first value to check
* @param right the second value to check
* @param valuesConsumer non-empty values consumer
* @since 0.0.9
*/
public static void ifBothNotEmpty(String left, String right, BiConsumer<String, String> valuesConsumer) {
if (isNotEmpty(left) && isNotEmpty(right)) {
valuesConsumer.accept(left, right);
}
}

/**
* Passes provided {@link String} pair if both of them not blank to the provided string {@link BiConsumer}
*
* @param left the first value to check
* @param right the second value to check
* @param valuesConsumer non-blank values consumer
* @since 0.0.9
*/
public static void ifBothNotBlank(String left, String right, BiConsumer<String, String> valuesConsumer) {
if (isNotBlank(left) && isNotBlank(right)) {
valuesConsumer.accept(left, right);
}
}
}
Loading

0 comments on commit d6d6e48

Please sign in to comment.