5 Commits

7 changed files with 707 additions and 338 deletions

View File

@@ -1,80 +0,0 @@
/*
* Copyright 2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.zhouxy.plusone.commons.math;
import java.util.Optional;
import javax.annotation.Nonnull;
import com.google.common.base.Preconditions;
import com.google.errorprone.annotations.Immutable;
import xyz.zhouxy.plusone.commons.util.Numbers;
@Immutable
public class Interval<T extends Comparable<T>> {
@Nonnull
private final IntervalType intervalType;
private final T lowerBound;
private final T upperBound;
public Interval(@Nonnull IntervalType intervalType, T lowerBound, T upperBound) {
Preconditions.checkNotNull(intervalType);
if (intervalType.isLeftClosed()) {
Preconditions.checkArgument(lowerBound != null,
"The lower bound cannot be null, when the interval is left-closed.");
}
if (intervalType.isRightClosed()) {
Preconditions.checkArgument(upperBound != null,
"The upper bound cannot be null, when the interval is right-closed.");
}
if (lowerBound != null && upperBound != null) {
Preconditions.checkArgument(lowerBound.compareTo(upperBound) <= 0,
"The lower bound must less than the upper bound.");
}
this.intervalType = intervalType;
this.lowerBound = lowerBound;
this.upperBound = upperBound;
}
@Nonnull
public final IntervalType getIntervalType() {
return intervalType;
}
@Nonnull
public final Optional<T> getLowerBound() {
return Optional.ofNullable(lowerBound);
}
@Nonnull
public final Optional<T> getUpperBound() {
return Optional.ofNullable(upperBound);
}
public final boolean isLeftClosed() {
return this.intervalType.isLeftClosed();
}
public final boolean isRightClosed() {
return this.intervalType.isRightClosed();
}
public final boolean validValue(@Nonnull T value) {
return Numbers.between(value, this.lowerBound, this.upperBound, this.intervalType);
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.zhouxy.plusone.commons.math;
public enum IntervalType {
/** 开区间。(a,b)={x|a < x < b} */
OPEN(false, false),
/** 闭区间。[a,b]={x|a ≤ x ≤ b} */
CLOSED(true, true),
/** 左闭右开区间。[a,b)={x|a ≤ x < b} */
CLOSED_OPEN(true, false),
/** 左开右闭区间。(a,b]={x|a < x ≤ b} */
OPEN_CLOSED(false, true);
private final boolean leftClosed;
private final boolean rightClosed;
IntervalType(boolean leftClosed, boolean rightClosed) {
this.leftClosed = leftClosed;
this.rightClosed = rightClosed;
}
public final boolean isLeftClosed() {
return leftClosed;
}
public final boolean isRightClosed() {
return rightClosed;
}
public final <T extends Comparable<T>> Interval<T> buildInterval(T left, T right) {
return new Interval<>(this, left, right);
}
}

View File

@@ -18,11 +18,11 @@ package xyz.zhouxy.plusone.commons.time;
import java.time.Month;
import java.time.MonthDay;
import java.time.temporal.ChronoField;
import com.google.common.base.Preconditions;
import com.google.common.collect.Range;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.commons.util.Numbers;
/**
* 季度
@@ -43,11 +43,7 @@ public enum Quarter {
/** 季度值 (1/2/3/4) */
private final int value;
/** 季度开始月份 */
private final int firstMonth;
/** 季度结束月份 */
private final int lastMonth;
private final Range<Integer> monthRange;
/** 常量值 */
private static final Quarter[] ENUMS = Quarter.values();
@@ -58,8 +54,10 @@ public enum Quarter {
Quarter(int value) {
this.value = value;
this.lastMonth = value * 3;
this.firstMonth = this.lastMonth - 2;
final int lastMonth = value * 3;
final int firstMonth = lastMonth - 2;
this.monthRange = Range.closed(firstMonth, lastMonth);
}
// StaticFactoryMethods
@@ -73,7 +71,7 @@ public enum Quarter {
*/
@StaticFactoryMethod(Quarter.class)
public static Quarter fromMonth(int monthValue) {
Preconditions.checkArgument(Numbers.between(monthValue, 1, 13), "Invalid value for MonthOfYear: " + monthValue);
ChronoField.MONTH_OF_YEAR.checkValidValue(monthValue);
return of(computeQuarterValueInternal(monthValue));
}
@@ -137,23 +135,23 @@ public enum Quarter {
}
public Month firstMonth() {
return Month.of(firstMonth);
return Month.of(firstMonthValue());
}
public int firstMonthValue() {
return firstMonth;
return this.monthRange.lowerEndpoint();
}
public Month lastMonth() {
return Month.of(lastMonth);
return Month.of(lastMonthValue());
}
public int lastMonthValue() {
return lastMonth;
return this.monthRange.upperEndpoint();
}
public MonthDay firstMonthDay() {
return MonthDay.of(this.firstMonth, 1);
return MonthDay.of(firstMonth(), 1);
}
public MonthDay lastMonthDay() {
@@ -163,7 +161,7 @@ public enum Quarter {
}
public int firstDayOfYear(boolean leapYear) {
return Month.of(this.firstMonth).firstDayOfYear(leapYear);
return firstMonth().firstDayOfYear(leapYear);
}
// Getters end

View File

@@ -16,10 +16,13 @@
package xyz.zhouxy.plusone.commons.util;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -29,13 +32,17 @@ public class ArrayTools {
// #region - empty arrays
public static final char[] EMPTY_CHAR_ARRAY = {};
public static final int[] EMPTY_INTEGER_ARRAY = {};
public static final byte[] EMPTY_BYTE_ARRAY = {};
public static final short[] EMPTY_SHORT_ARRAY = {};
public static final int[] EMPTY_INT_ARRAY = {};
public static final long[] EMPTY_LONG_ARRAY = {};
public static final float[] EMPTY_FLOAT_ARRAY = {};
public static final double[] EMPTY_DOUBLE_ARRAY = {};
// #endregion
public static final int NOT_FOUND_INDEX = -1;
// #region - isNullOrEmpty
// isNullOrEmpty
@@ -51,6 +58,61 @@ public class ArrayTools {
return arr == null || arr.length == 0;
}
// isNullOrEmpty - char
/**
* 检查给定数组是否为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组为 {@code null} 或长度为 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNullOrEmpty(@Nullable char[] arr) {
return arr == null || arr.length == 0;
}
// isNullOrEmpty - byte
/**
* 检查给定数组是否为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组为 {@code null} 或长度为 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNullOrEmpty(@Nullable byte[] arr) {
return arr == null || arr.length == 0;
}
// isNullOrEmpty - short
/**
* 检查给定数组是否为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组为 {@code null} 或长度为 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNullOrEmpty(@Nullable short[] arr) {
return arr == null || arr.length == 0;
}
// isNullOrEmpty - int
/**
* 检查给定数组是否为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组为 {@code null} 或长度为 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNullOrEmpty(@Nullable int[] arr) {
return arr == null || arr.length == 0;
}
// isNullOrEmpty - long
/**
* 检查给定数组是否为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组为 {@code null} 或长度为 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNullOrEmpty(@Nullable long[] arr) {
return arr == null || arr.length == 0;
}
// isNullOrEmpty - float
/**
* 检查给定数组是否为空
@@ -73,39 +135,6 @@ public class ArrayTools {
return arr == null || arr.length == 0;
}
// isNullOrEmpty - byte
/**
* 检查给定数组是否为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组为 {@code null} 或长度为 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNullOrEmpty(@Nullable byte[] arr) {
return arr == null || arr.length == 0;
}
// isNullOrEmpty - long
/**
* 检查给定数组是否为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组为 {@code null} 或长度为 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNullOrEmpty(@Nullable long[] arr) {
return arr == null || arr.length == 0;
}
// isNullOrEmpty - int
/**
* 检查给定数组是否为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组为 {@code null} 或长度为 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNullOrEmpty(@Nullable int[] arr) {
return arr == null || arr.length == 0;
}
// #endregion
// #region - isNotEmpty
@@ -122,6 +151,61 @@ public class ArrayTools {
return arr != null && arr.length > 0;
}
// isNotEmpty - char
/**
* 检查给定数组是否不为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组不为 {@code null} 且长度大于 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNotEmpty(@Nullable char[] arr) {
return arr != null && arr.length > 0;
}
// isNotEmpty - byte
/**
* 检查给定数组是否不为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组不为 {@code null} 且长度大于 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNotEmpty(@Nullable byte[] arr) {
return arr != null && arr.length > 0;
}
// isNotEmpty - short
/**
* 检查给定数组是否不为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组不为 {@code null} 且长度大于 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNotEmpty(@Nullable short[] arr) {
return arr != null && arr.length > 0;
}
// isNotEmpty - int
/**
* 检查给定数组是否不为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组不为 {@code null} 且长度大于 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNotEmpty(@Nullable int[] arr) {
return arr != null && arr.length > 0;
}
// isNotEmpty - long
/**
* 检查给定数组是否不为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组不为 {@code null} 且长度大于 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNotEmpty(@Nullable long[] arr) {
return arr != null && arr.length > 0;
}
// isNotEmpty - float
/**
* 检查给定数组是否不为空
@@ -144,39 +228,6 @@ public class ArrayTools {
return arr != null && arr.length > 0;
}
// isNotEmpty - byte
/**
* 检查给定数组是否不为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组不为 {@code null} 且长度大于 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNotEmpty(@Nullable byte[] arr) {
return arr != null && arr.length > 0;
}
// isNotEmpty - long
/**
* 检查给定数组是否不为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组不为 {@code null} 且长度大于 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNotEmpty(@Nullable long[] arr) {
return arr != null && arr.length > 0;
}
// isNotEmpty - int
/**
* 检查给定数组是否不为空
*
* @param arr 待检查的数组,可以为 {@code null}
* @return 如果数组不为 {@code null} 且长度大于 0则返回 {@code true};否则返回 {@code false}
*/
public static boolean isNotEmpty(@Nullable int[] arr) {
return arr != null && arr.length > 0;
}
// #endregion
// #region - isAllElementsNotNull
@@ -216,34 +267,14 @@ public class ArrayTools {
* @param arrays 数组集合,可以为 {@code null}
* @return 拼接后的数组
*/
public static float[] concatFloatArray(@Nullable Collection<float[]> arrays) {
public static char[] concatCharArray(@Nullable Collection<char[]> arrays) {
if (arrays == null || arrays.isEmpty()) {
return new float[0];
return new char[0];
}
final int length = arrays.stream().mapToInt(a -> a.length).sum();
final float[] result = new float[length];
final char[] result = new char[length];
int i = 0;
for (float[] arr : arrays) {
System.arraycopy(arr, 0, result, i, arr.length);
i += arr.length;
}
return result;
}
/**
* 拼接多个数组
*
* @param arrays 数组集合,可以为 {@code null}
* @return 拼接后的数组
*/
public static double[] concatDoubleArray(@Nullable Collection<double[]> arrays) {
if (arrays == null || arrays.isEmpty()) {
return new double[0];
}
final int length = arrays.stream().mapToInt(a -> a.length).sum();
final double[] result = new double[length];
int i = 0;
for (double[] arr : arrays) {
for (char[] arr : arrays) {
System.arraycopy(arr, 0, result, i, arr.length);
i += arr.length;
}
@@ -276,14 +307,14 @@ public class ArrayTools {
* @param arrays 数组集合,可以为 {@code null}
* @return 拼接后的数组
*/
public static long[] concatLongArray(@Nullable Collection<long[]> arrays) {
public static short[] concatShortArray(@Nullable Collection<short[]> arrays) {
if (arrays == null || arrays.isEmpty()) {
return new long[0];
return new short[0];
}
final int length = arrays.stream().mapToInt(a -> a.length).sum();
final long[] result = new long[length];
final short[] result = new short[length];
int i = 0;
for (long[] arr : arrays) {
for (short[] arr : arrays) {
System.arraycopy(arr, 0, result, i, arr.length);
i += arr.length;
}
@@ -310,6 +341,66 @@ public class ArrayTools {
return result;
}
/**
* 拼接多个数组
*
* @param arrays 数组集合,可以为 {@code null}
* @return 拼接后的数组
*/
public static long[] concatLongArray(@Nullable Collection<long[]> arrays) {
if (arrays == null || arrays.isEmpty()) {
return new long[0];
}
final int length = arrays.stream().mapToInt(a -> a.length).sum();
final long[] result = new long[length];
int i = 0;
for (long[] arr : arrays) {
System.arraycopy(arr, 0, result, i, arr.length);
i += arr.length;
}
return result;
}
/**
* 拼接多个数组
*
* @param arrays 数组集合,可以为 {@code null}
* @return 拼接后的数组
*/
public static float[] concatFloatArray(@Nullable Collection<float[]> arrays) {
if (arrays == null || arrays.isEmpty()) {
return new float[0];
}
final int length = arrays.stream().mapToInt(a -> a.length).sum();
final float[] result = new float[length];
int i = 0;
for (float[] arr : arrays) {
System.arraycopy(arr, 0, result, i, arr.length);
i += arr.length;
}
return result;
}
/**
* 拼接多个数组
*
* @param arrays 数组集合,可以为 {@code null}
* @return 拼接后的数组
*/
public static double[] concatDoubleArray(@Nullable Collection<double[]> arrays) {
if (arrays == null || arrays.isEmpty()) {
return new double[0];
}
final int length = arrays.stream().mapToInt(a -> a.length).sum();
final double[] result = new double[length];
int i = 0;
for (double[] arr : arrays) {
System.arraycopy(arr, 0, result, i, arr.length);
i += arr.length;
}
return result;
}
/**
* 将集合中的数组连接为一个列表
*
@@ -360,6 +451,69 @@ public class ArrayTools {
return result;
}
// repeat - byte
public static byte[] repeat(byte[] arr, int times) {
return repeat(arr, times, Integer.MAX_VALUE);
}
public static byte[] repeat(byte[] arr, int times, int maxLength) {
AssertTools.checkArgumentNotNull(arr);
AssertTools.checkArgument(times >= 0,
"The number of times must be greater than or equal to zero");
AssertTools.checkArgument(maxLength >= 0,
"The max length must be greater than or equal to zero");
if (times == 0) {
return EMPTY_BYTE_ARRAY;
}
final int length = Integer.min(arr.length * times, maxLength);
final byte[] result = new byte[length];
fill(result, 0, length, arr);
return result;
}
// repeat - short
public static short[] repeat(short[] arr, int times) {
return repeat(arr, times, Integer.MAX_VALUE);
}
public static short[] repeat(short[] arr, int times, int maxLength) {
AssertTools.checkArgumentNotNull(arr);
AssertTools.checkArgument(times >= 0,
"The number of times must be greater than or equal to zero");
AssertTools.checkArgument(maxLength >= 0,
"The max length must be greater than or equal to zero");
if (times == 0) {
return EMPTY_SHORT_ARRAY;
}
final int length = Integer.min(arr.length * times, maxLength);
final short[] result = new short[length];
fill(result, 0, length, arr);
return result;
}
// repeat - int
public static int[] repeat(int[] arr, int times) {
return repeat(arr, times, Integer.MAX_VALUE);
}
public static int[] repeat(int[] arr, int times, int maxLength) {
AssertTools.checkArgumentNotNull(arr);
AssertTools.checkArgument(times >= 0,
"The number of times must be greater than or equal to zero");
AssertTools.checkArgument(maxLength >= 0,
"The max length must be greater than or equal to zero");
if (times == 0) {
return EMPTY_INT_ARRAY;
}
final int length = Integer.min(arr.length * times, maxLength);
final int[] result = new int[length];
fill(result, 0, length, arr);
return result;
}
// repeat - long
public static long[] repeat(long[] arr, int times) {
@@ -460,6 +614,93 @@ public class ArrayTools {
}
}
// fill - byte
public static void fill(byte[] a, byte... values) {
fill(a, 0, a.length, values);
}
public static void fill(byte[] a, int fromIndex, int toIndex, byte... values) {
AssertTools.checkArgumentNotNull(a);
if (values.length == 0) {
return;
}
final int start = Integer.max(fromIndex, 0);
final int end = Integer.min(toIndex, a.length);
if (start >= end) {
return;
}
for (int i = start; i < end; i += values.length) {
for (int j = 0; j < values.length; j++) {
final int k = (i + j);
if (k < end) {
a[k] = values[j];
}
else {
break;
}
}
}
}
// fill - short
public static void fill(short[] a, short... values) {
fill(a, 0, a.length, values);
}
public static void fill(short[] a, int fromIndex, int toIndex, short... values) {
AssertTools.checkArgumentNotNull(a);
if (values.length == 0) {
return;
}
final int start = Integer.max(fromIndex, 0);
final int end = Integer.min(toIndex, a.length);
if (start >= end) {
return;
}
for (int i = start; i < end; i += values.length) {
for (int j = 0; j < values.length; j++) {
final int k = (i + j);
if (k < end) {
a[k] = values[j];
}
else {
break;
}
}
}
}
// fill - int
public static void fill(int[] a, int... values) {
fill(a, 0, a.length, values);
}
public static void fill(int[] a, int fromIndex, int toIndex, int... values) {
AssertTools.checkArgumentNotNull(a);
if (values.length == 0) {
return;
}
final int start = Integer.max(fromIndex, 0);
final int end = Integer.min(toIndex, a.length);
if (start >= end) {
return;
}
for (int i = start; i < end; i += values.length) {
for (int j = 0; j < values.length; j++) {
final int k = (i + j);
if (k < end) {
a[k] = values[j];
}
else {
break;
}
}
}
}
// fill - long
public static void fill(long[] a, long... values) {
@@ -582,6 +823,256 @@ public class ArrayTools {
// #endregion
// #region - indexOf
public static <T> int indexOf(T[] arr, Predicate<? super T> predicate) { // TODO 单元测试
AssertTools.checkNotNull(predicate);
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = 0; i < arr.length; i++) {
if (predicate.test(arr[i])) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static <T> int indexOf(T[] arr, T obj) { // TODO 单元测试
return indexOf(arr, item -> Objects.equals(item, obj));
}
public static int indexOf(char[] arr, char value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static int indexOf(byte[] arr, byte value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static int indexOf(short[] arr, short value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static int indexOf(int[] arr, int value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static int indexOf(long[] arr, long value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static int indexOf(float[] arr, float value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static int indexOf(double[] arr, double value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return NOT_FOUND_INDEX;
}
// #endregion
// #region - lastIndexOf
public static <T> int lastIndexOf(T[] arr, @Nonnull Predicate<? super T> predicate) { // TODO 单元测试
AssertTools.checkNotNull(predicate);
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = arr.length - 1; i >= 0; i--) {
if (predicate.test(arr[i])) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static <T> int lastIndexOf(T[] arr, T obj) { // TODO 单元测试
return lastIndexOf(arr, item -> Objects.equals(item, obj));
}
public static <T> int lastIndexOf(char[] arr, char value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = arr.length - 1; i >= 0; i--) {
if (value == arr[i]) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static <T> int lastIndexOf(byte[] arr, byte value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = arr.length - 1; i >= 0; i--) {
if (value == arr[i]) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static <T> int lastIndexOf(short[] arr, short value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = arr.length - 1; i >= 0; i--) {
if (value == arr[i]) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static <T> int lastIndexOf(int[] arr, int value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = arr.length - 1; i >= 0; i--) {
if (value == arr[i]) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static <T> int lastIndexOf(long[] arr, long value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = arr.length - 1; i >= 0; i--) {
if (value == arr[i]) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static <T> int lastIndexOf(float[] arr, float value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = arr.length - 1; i >= 0; i--) {
if (value == arr[i]) {
return i;
}
}
return NOT_FOUND_INDEX;
}
public static <T> int lastIndexOf(double[] arr, double value) { // TODO 单元测试
if (isNullOrEmpty(arr)) {
return NOT_FOUND_INDEX;
}
for (int i = arr.length - 1; i >= 0; i--) {
if (value == arr[i]) {
return i;
}
}
return NOT_FOUND_INDEX;
}
// #endregion
// #region - contains
public static <T> boolean contains(T[] arr, T obj) { // TODO 单元测试
return indexOf(arr, obj) > NOT_FOUND_INDEX;
}
public static boolean contains(char[] arr, char obj) { // TODO 单元测试
return indexOf(arr, obj) > NOT_FOUND_INDEX;
}
public static boolean contains(byte[] arr, byte obj) { // TODO 单元测试
return indexOf(arr, obj) > NOT_FOUND_INDEX;
}
public static boolean contains(short[] arr, short obj) { // TODO 单元测试
return indexOf(arr, obj) > NOT_FOUND_INDEX;
}
public static boolean contains(int[] arr, int obj) { // TODO 单元测试
return indexOf(arr, obj) > NOT_FOUND_INDEX;
}
public static boolean contains(long[] arr, long obj) { // TODO 单元测试
return indexOf(arr, obj) > NOT_FOUND_INDEX;
}
public static boolean contains(float[] arr, float obj) { // TODO 单元测试
return indexOf(arr, obj) > NOT_FOUND_INDEX;
}
public static boolean contains(double[] arr, double obj) { // TODO 单元测试
return indexOf(arr, obj) > NOT_FOUND_INDEX;
}
public static boolean containsValue(BigDecimal[] arr, BigDecimal obj) { // TODO 单元测试
return indexOf(arr, item -> BigDecimals.equalsValue(item, obj)) > NOT_FOUND_INDEX;
}
// #endregion
// #region - private constructor
private ArrayTools() {

View File

@@ -17,6 +17,8 @@
package xyz.zhouxy.plusone.commons.util;
import java.math.BigDecimal;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.base.Preconditions;
@@ -49,6 +51,25 @@ public class BigDecimals {
return lt(a, b) || equalsValue(a, b);
}
public static BigDecimal sum(final BigDecimal... numbers) {
if (ArrayTools.isNullOrEmpty(numbers)) {
return BigDecimal.ZERO;
}
BigDecimal result = BigDecimals.nullToZero(numbers[0]);
for (int i = 1; i < numbers.length; i++) {
BigDecimal value = numbers[i];
if (value != null) {
result = result.add(value);
}
}
return result;
}
@Nonnull
public static BigDecimal nullToZero(@Nullable final BigDecimal val) {
return val != null ? val : BigDecimal.ZERO;
}
@StaticFactoryMethod(BigDecimal.class)
public static BigDecimal of(final String val) {
return (StringTools.isNotBlank(val)) ? new BigDecimal(val) : BigDecimal.ZERO;

View File

@@ -67,6 +67,8 @@ public class DateTimeTools {
return DATE_TIME_FORMATTER_CACHE.getUnchecked(pattern);
}
// #region - toString
/**
* 将日期时间转换为指定格式的字符串
*
@@ -103,6 +105,10 @@ public class DateTimeTools {
return toString(pattern, dateTime);
}
// #endregion
// #region - nowStr
/**
* 指定格式,返回当前时间戳对应的字符串
*
@@ -124,7 +130,9 @@ public class DateTimeTools {
return toString(pattern, Instant.now().atZone(zone));
}
// toDate
// #endregion
// #region - toDate
/**
* 将时间戳转换为 {@link Date} 对象
@@ -189,7 +197,9 @@ public class DateTimeTools {
return Date.from(ZonedDateTime.of(localDate, localTime, zone).toInstant());
}
// toInstant
// #endregion
// #region - toInstant
/**
* 将时间戳转换为 {@link Instant} 对象
@@ -244,7 +254,9 @@ public class DateTimeTools {
return ZonedDateTime.of(localDateTime, zone).toInstant();
}
// toZonedDateTime
// #endregion
// #region - toZonedDateTime
/**
* 获取时间戳在指定时区的地区时间。
@@ -338,7 +350,9 @@ public class DateTimeTools {
return ZonedDateTime.of(localDateTime, zone);
}
// toLocalDateTime
// #endregion
// #region - toLocalDateTime
/**
* 获取时间戳在指定时区的地区时间。
@@ -406,9 +420,11 @@ public class DateTimeTools {
return LocalDateTime.ofInstant(zonedDateTime.toInstant(), zone);
}
// #endregion
// ====================
// toJodaInstant
// #region - toJodaInstant
/**
* 将 {@link java.time.Instant} 转换为 {@link org.joda.time.Instant}
@@ -441,7 +457,9 @@ public class DateTimeTools {
return toJodaInstant(java.time.ZonedDateTime.of(localDateTime, zone));
}
// toJavaInstant
// #endregion
// #region - toJavaInstant
/**
* 将 {@link org.joda.time.Instant} 对象转换为 {@link java.time.Instant} 对象
@@ -479,7 +497,9 @@ public class DateTimeTools {
return toJavaInstant(localDateTime.toDateTime(zone));
}
// toJodaDateTime
// #endregion
// #region - toJodaDateTime
/**
* 将 Java 中表示日期时间的 {@link java.time.ZonedDateTime} 对象
@@ -506,7 +526,7 @@ public class DateTimeTools {
public static org.joda.time.DateTime toJodaDateTime(
java.time.LocalDateTime localDateTime,
java.time.ZoneId zone) {
org.joda.time.DateTimeZone dateTimeZone = toJodaTime(zone);
org.joda.time.DateTimeZone dateTimeZone = toJodaZone(zone);
return toJodaInstant(ZonedDateTime.of(localDateTime, zone).toInstant()).toDateTime(dateTimeZone);
}
@@ -520,11 +540,13 @@ public class DateTimeTools {
public static org.joda.time.DateTime toJodaDateTime(
java.time.Instant instant,
java.time.ZoneId zone) {
org.joda.time.DateTimeZone dateTimeZone = toJodaTime(zone);
org.joda.time.DateTimeZone dateTimeZone = toJodaZone(zone);
return toJodaInstant(instant).toDateTime(dateTimeZone);
}
// toZonedDateTime
// #endregion
// #region - toZonedDateTime
/**
* 将 joda-time 中带时区的日期时间,转换为 java.time 中带时区的日期时间
@@ -568,7 +590,9 @@ public class DateTimeTools {
return toJavaInstant(instant).atZone(zone);
}
// toJodaLocalDateTime
// #endregion
// #region - toJodaLocalDateTime
/**
* 将 {@link java.time.LocalDateTime} 转换为 {@link org.joda.time.LocalDateTime}
@@ -578,11 +602,13 @@ public class DateTimeTools {
*/
public static org.joda.time.LocalDateTime toJodaLocalDateTime(java.time.LocalDateTime localDateTime) {
java.time.ZoneId javaZone = java.time.ZoneId.systemDefault();
org.joda.time.DateTimeZone jodaZone = toJodaTime(javaZone);
org.joda.time.DateTimeZone jodaZone = toJodaZone(javaZone);
return toJodaInstant(localDateTime, javaZone).toDateTime(jodaZone).toLocalDateTime();
}
// toJavaLocalDateTime
// #endregion
// #region - toJavaLocalDateTime
/**
* 将 {@link org.joda.time.LocalDateTime} 转换为 {@link java.time.LocalDateTime}
@@ -596,6 +622,10 @@ public class DateTimeTools {
return toJavaInstant(localDateTime, jodaZone).atZone(javaZone).toLocalDateTime();
}
// #endregion
// #region - ZoneId <--> DateTimeZone
/**
* 转换 Java API 和 joda-time API 表示时区的对象
*
@@ -612,11 +642,13 @@ public class DateTimeTools {
* @param zone Java API 中表示时区的对象
* @return joda-time API 中表示时区的对象
*/
public static org.joda.time.DateTimeZone toJodaTime(java.time.ZoneId zone) {
public static org.joda.time.DateTimeZone toJodaZone(java.time.ZoneId zone) {
return org.joda.time.DateTimeZone.forID(zone.getId());
}
// getQuarter
// #endregion
// #region - YearQuarter & Quarter
/**
* 获取指定日期所在季度
@@ -679,6 +711,8 @@ public class DateTimeTools {
return YearQuarter.of(date);
}
// #endregion
/**
* 私有构造方法,明确标识该常量类的作用。
*/

View File

@@ -17,12 +17,10 @@
package xyz.zhouxy.plusone.commons.util;
import java.math.BigDecimal;
import java.math.BigInteger;
import javax.annotation.Nonnull;
import com.google.common.base.Preconditions;
import xyz.zhouxy.plusone.commons.math.IntervalType;
import javax.annotation.Nullable;
/**
* Numbers
@@ -31,7 +29,7 @@ import xyz.zhouxy.plusone.commons.math.IntervalType;
*/
public class Numbers {
// sum
// #region - sum
public static int sum(final short... numbers) {
int result = 0;
@@ -73,105 +71,60 @@ public class Numbers {
return result;
}
public static BigDecimal sum(final BigDecimal... numbers) {
BigDecimal result = BigDecimals.of("0.00");
for (BigDecimal number : numbers) {
result = result.add(number);
public static BigInteger sum(final BigInteger... numbers) {
if (ArrayTools.isNullOrEmpty(numbers)) {
return BigInteger.ZERO;
}
BigInteger result = Numbers.nullToZero(numbers[0]);
for (int i = 1; i < numbers.length; i++) {
BigInteger value = numbers[i];
if (value != null) {
result = result.add(value);
}
}
return result;
}
// between
public static boolean between(int value, int min, int max) {
return between(value, min, max, IntervalType.CLOSED_OPEN);
public static BigDecimal sum(final BigDecimal... numbers) {
return BigDecimals.sum(numbers);
}
public static boolean between(int value, int min, int max, IntervalType intervalType) {
final IntervalType intervalTypeToUse = intervalType != null
? intervalType
: IntervalType.CLOSED_OPEN;
switch (intervalTypeToUse) {
case OPEN:
return min < value && value < max;
case CLOSED:
return min <= value && value <= max;
case OPEN_CLOSED:
return min < value && value <= max;
case CLOSED_OPEN:
default:
return min <= value && value < max;
}
// #endregion
// #region - nullToZero
public static short nullToZero(@Nullable final Short val) {
return val != null ? val : 0;
}
public static boolean between(long value, long min, long max) {
return between(value, min, max, IntervalType.CLOSED_OPEN);
public static int nullToZero(@Nullable final Integer val) {
return val != null ? val : 0;
}
public static boolean between(long value, long min, long max, IntervalType intervalType) {
final IntervalType intervalTypeToUse = intervalType != null
? intervalType
: IntervalType.CLOSED_OPEN;
switch (intervalTypeToUse) {
case OPEN:
return min < value && value < max;
case CLOSED:
return min <= value && value <= max;
case OPEN_CLOSED:
return min < value && value <= max;
case CLOSED_OPEN:
default:
return min <= value && value < max;
}
public static long nullToZero(@Nullable final Long val) {
return val != null ? val : 0L;
}
public static boolean between(double value, double min, double max) {
return between(value, min, max, IntervalType.CLOSED_OPEN);
public static float nullToZero(@Nullable final Float val) {
return val != null ? val : 0.0F;
}
public static boolean between(double value, double min, double max, IntervalType intervalType) {
final IntervalType intervalTypeToUse = intervalType != null
? intervalType
: IntervalType.CLOSED_OPEN;
switch (intervalTypeToUse) {
case OPEN:
return min < value && value < max;
case CLOSED:
return min <= value && value <= max;
case OPEN_CLOSED:
return min < value && value <= max;
case CLOSED_OPEN:
default:
return min <= value && value < max;
}
public static double nullToZero(@Nullable final Double val) {
return val != null ? val : 0.0;
}
public static <T extends Comparable<T>> boolean between(@Nonnull T value, T min, T max) {
return between(value, min, max, IntervalType.CLOSED_OPEN);
@Nonnull
public static BigInteger nullToZero(@Nullable final BigInteger val) {
return val != null ? val : BigInteger.ZERO;
}
public static <T extends Comparable<T>> boolean between(@Nonnull T value, T min, T max, IntervalType intervalType) {
Preconditions.checkArgument(value != null, "The value to valid connot be null.");
IntervalType intervalTypeToUse = intervalType != null
? intervalType
: IntervalType.CLOSED_OPEN;
switch (intervalTypeToUse) {
case OPEN:
return (min == null || min.compareTo(value) < 0)
&& (max == null || value.compareTo(max) < 0);
case CLOSED:
return (min == null || min.compareTo(value) <= 0)
&& (max == null || value.compareTo(max) <= 0);
case OPEN_CLOSED:
return (min == null || min.compareTo(value) < 0)
&& (max == null || value.compareTo(max) <= 0);
case CLOSED_OPEN:
default:
return (min == null || min.compareTo(value) <= 0)
&& (max == null || value.compareTo(max) < 0);
}
@Nonnull
public static BigDecimal nullToZero(@Nullable final BigDecimal val) {
return BigDecimals.nullToZero(val);
}
// #endregion
private Numbers() {
throw new IllegalStateException("Utility class");
}