Skip to content

Commit

Permalink
refactor: use normal array list instead of immutable(`Collections#emp…
Browse files Browse the repository at this point in the history
…tyList`) or fixed-size(`Arrays#asList`) list ⛑️

Safer for application codes which may reuse the returned list as normal collection.
  • Loading branch information
oldratlee committed Apr 22, 2024
1 parent ff39ca6 commit d9568ba
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 54 deletions.
13 changes: 4 additions & 9 deletions cffu-core/src/main/java/io/foldright/cffu/CffuFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.concurrent.ThreadSafe;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
Expand Down Expand Up @@ -591,8 +590,7 @@ public Executor delayedExecutor(long delay, TimeUnit unit, Executor executor) {
* Returns a new Cffu that is completed when all the given Cffus complete.
* If any of the given Cffus complete exceptionally, then the returned Cffu
* also does so, with a CompletionException holding this exception as its cause.
* If no Cffus are provided, returns a Cffu completed
* with the value {@link java.util.Collections#emptyList() emptyList}.
* If no Cffus are provided, returns a Cffu completed with the value empty list.
* <p>
* Same to {@link #allOf(Cffu[])}, but the returned Cffu
* contains the results of input Cffus.
Expand All @@ -613,8 +611,7 @@ public final <T> Cffu<List<T>> cffuAllOf(Cffu<T>... cfs) {
* the new Cffu is completed when all the given CompletableFutures complete.
* If any of the given CompletableFutures complete exceptionally, then the returned Cffu
* also does so, with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a Cffu completed
* with the value {@link java.util.Collections#emptyList() emptyList}.
* If no CompletableFutures are provided, returns a Cffu completed with the value empty list.
* <p>
* Same as {@link #cffuAllOf(Cffu[])} with overloaded argument type {@link CompletableFuture}.
*
Expand Down Expand Up @@ -647,8 +644,7 @@ public <T> Cffu<List<T>> cffuAllOf() {
* If any of the given Cffus complete exceptionally, then the returned Cffu
* also does so *without* waiting other incomplete given Cffus,
* with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a Cffu completed
* with the value {@link Collections#emptyList() emptyList}.
* If no CompletableFutures are provided, returns a Cffu completed with the value empty list.
*
* @param cfs the CompletableFutures
* @return a new CompletableFuture that is successful when all the given CompletableFutures success
Expand All @@ -668,8 +664,7 @@ public final <T> Cffu<List<T>> cffuAllOfFastFail(Cffu<T>... cfs) {
* If any of the given CompletableFutures complete exceptionally, then the returned Cffu
* also does so *without* waiting other incomplete given CompletableFutures,
* with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a Cffu completed
* with the value {@link Collections#emptyList() emptyList}.
* If no CompletableFutures are provided, returns a Cffu completed with the value empty list.
* <p>
* Same as {@link #cffuAllOfFastFail(Cffu[])} with overloaded argument type {@link CompletableFuture}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
import org.jetbrains.annotations.Contract;

import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
import java.util.function.Function;
Expand All @@ -37,8 +37,7 @@ public final class CompletableFutureUtils {
* CompletableFutures, the new CompletableFuture is completed when all the given CompletableFutures complete.
* If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture
* also does so, with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a CompletableFuture completed
* with the value {@link Collections#emptyList() emptyList}.
* If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list.
* <p>
* Same to {@link CompletableFuture#allOf(CompletableFuture[])},
* but the returned CompletableFuture contains the results of the given CompletableFutures.
Expand All @@ -54,8 +53,8 @@ public final class CompletableFutureUtils {
public static <T> CompletableFuture<List<T>> allOfWithResult(CompletableFuture<T>... cfs) {
requireCfsAndEleNonNull(cfs);
final int size = cfs.length;
if (size == 0) return CompletableFuture.completedFuture(Collections.emptyList());
if (size == 1) return cfs[0].thenApply(Arrays::asList);
if (size == 0) return CompletableFuture.completedFuture(arrayList());
if (size == 1) return cfs[0].thenApply(CompletableFutureUtils::arrayList);

final Object[] result = new Object[size];

Expand All @@ -66,7 +65,7 @@ public static <T> CompletableFuture<List<T>> allOfWithResult(CompletableFuture<T
}

return CompletableFuture.allOf(collectResultCfs)
.thenApply(unused -> (List<T>) Arrays.asList(result));
.thenApply(unused -> (List<T>) arrayList(result));
}

/**
Expand Down Expand Up @@ -109,8 +108,7 @@ public static CompletableFuture<Void> allOfFastFail(CompletableFuture<?>... cfs)
* If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture
* also does so *without* waiting other incomplete given CompletableFutures,
* with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a CompletableFuture completed
* with the value {@link Collections#emptyList() emptyList}.
* If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list.
* <p>
* Same to {@link #allOfFastFail(CompletableFuture[])},
* but the returned CompletableFuture contains the results of the given CompletableFutures.
Expand All @@ -126,8 +124,8 @@ public static CompletableFuture<Void> allOfFastFail(CompletableFuture<?>... cfs)
public static <T> CompletableFuture<List<T>> allOfFastFailWithResult(CompletableFuture<T>... cfs) {
requireCfsAndEleNonNull(cfs);
final int size = cfs.length;
if (size == 0) return CompletableFuture.completedFuture(Collections.emptyList());
if (size == 1) return cfs[0].thenApply(Arrays::asList);
if (size == 0) return CompletableFuture.completedFuture(arrayList());
if (size == 1) return cfs[0].thenApply(CompletableFutureUtils::arrayList);

final CompletableFuture[] successOrBeIncomplete = new CompletableFuture[size];
// NOTE: fill ONE MORE element of failedOrBeIncomplete LATER
Expand All @@ -148,6 +146,17 @@ private static void requireCfsAndEleNonNull(CompletableFuture<?>... cfs) {
}
}

/**
* Returns normal array list instead of unmodifiable or fixed-size list.
* Safer for application code which may reuse the returned list as normal collection.
*/
@SuppressWarnings("unchecked")
private static <T> List<T> arrayList(T... elements) {
List<T> ret = new ArrayList<>(elements.length);
ret.addAll(Arrays.asList(elements));
return ret;
}

@SuppressWarnings({"unchecked", "rawtypes"})
private static void fill(CompletableFuture[] cfs,
CompletableFuture[] successOrBeIncomplete,
Expand Down Expand Up @@ -609,7 +618,7 @@ public static <T> CompletableFuture<T> exceptionallyAsync(
public static <T> CompletableFuture<T> exceptionallyAsync(
CompletableFuture<T> cf, Function<Throwable, ? extends T> fn, Executor executor) {
if (IS_JAVA12_PLUS) {
return (cf.exceptionallyAsync(fn, executor));
return cf.exceptionallyAsync(fn, executor);
}

// below code is copied from CompletionStage#exceptionallyAsync
Expand All @@ -631,8 +640,7 @@ public static <T> CompletableFuture<T> exceptionallyAsync(
*/
public static <T> CompletableFuture<T> orTimeout(CompletableFuture<T> cf, long timeout, TimeUnit unit) {
if (IS_JAVA9_PLUS) {
cf.orTimeout(timeout, unit);
return cf;
return cf.orTimeout(timeout, unit);
}

// below code is copied from CompletableFuture#orTimeout with small adoption
Expand All @@ -656,8 +664,7 @@ public static <T> CompletableFuture<T> orTimeout(CompletableFuture<T> cf, long t
public static <T> CompletableFuture<T> completeOnTimeout(
CompletableFuture<T> cf, @Nullable T value, long timeout, TimeUnit unit) {
if (IS_JAVA9_PLUS) {
cf.completeOnTimeout(value, timeout, unit);
return cf;
return cf.completeOnTimeout(value, timeout, unit);
}

// below code is copied from CompletableFuture#completeOnTimeout with small adoption
Expand All @@ -683,7 +690,7 @@ public static <T> CompletableFuture<T> completeOnTimeout(
public static <T> CompletableFuture<T> exceptionallyCompose(
CompletableFuture<T> cf, Function<Throwable, ? extends CompletionStage<T>> fn) {
if (IS_JAVA12_PLUS) {
return (cf.exceptionallyCompose(fn));
return cf.exceptionallyCompose(fn);
}

// below code is copied from CompletionStage.exceptionallyCompose
Expand Down Expand Up @@ -911,8 +918,7 @@ public static <T> CompletableFuture<T> completeAsync(CompletableFuture<T> cf, Su
public static <T> CompletableFuture<T> completeAsync(
CompletableFuture<T> cf, Supplier<? extends T> supplier, Executor executor) {
if (IS_JAVA9_PLUS) {
cf.completeAsync(supplier, executor);
return cf;
return cf.completeAsync(supplier, executor);
}

// below code is copied from CompletableFuture#completeAsync with small adoption
Expand Down Expand Up @@ -971,9 +977,9 @@ public static <T> CompletableFuture<T> copy(CompletableFuture<T> cf) {
@Contract(pure = true)
public static <T, U> CompletableFuture<U> newIncompleteFuture(CompletableFuture<T> cf) {
if (IS_JAVA9_PLUS) {
return (cf.newIncompleteFuture());
return cf.newIncompleteFuture();
}
return (new CompletableFuture<>());
return new CompletableFuture<>();
}

//# Getter methods
Expand Down Expand Up @@ -1006,7 +1012,7 @@ static Executor screenExecutor(Executor e) {
return requireNonNull(e, "defaultExecutor is null");
}

private static final boolean USE_COMMON_POOL = (ForkJoinPool.getCommonPoolParallelism() > 1);
private static final boolean USE_COMMON_POOL = ForkJoinPool.getCommonPoolParallelism() > 1;

/**
* Fallback if ForkJoinPool.commonPool() cannot support parallelism
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ private const val ERROR_MSG_FOR_ARRAY = "no cffuFactory argument provided when t
* the new Cffu is completed when all the given Cffus complete.
* If any of the given Cffus complete exceptionally, then the returned Cffu
* also does so, with a CompletionException holding this exception as its cause.
* If no Cffus are provided, returns a Cffu completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no Cffus are provided, returns a Cffu completed with the value empty list.
*
* Same as [allOfCffuVoid], but the returned Cffu contains the results of input Cffus.
* Same as [CffuFactory.cffuAllOf], providing this method is convenient for method chaining.
Expand All @@ -91,8 +90,7 @@ fun <T> Collection<Cffu<T>>.allOfCffu(cffuFactory: CffuFactory = ABSENT): Cffu<L
* the new Cffu is completed when all the given Cffus complete.
* If any of the given Cffus complete exceptionally, then the returned Cffu
* also does so, with a CompletionException holding this exception as its cause.
* If no Cffus are provided, returns a Cffu completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no Cffus are provided, returns a Cffu completed with the value empty list.
*
* Same as [allOfCffuVoid], but the returned Cffu contains the results of input Cffus.
* Same as [CffuFactory.cffuAllOf], providing this method is convenient for method chaining.
Expand All @@ -114,8 +112,7 @@ fun <T> Array<Cffu<T>>.allOfCffu(cffuFactory: CffuFactory = ABSENT): Cffu<List<T
* the new Cffu is completed when all the given CompletableFutures complete.
* If any of the given CompletableFutures complete exceptionally, then the returned Cffu
* also does so, with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a Cffu completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a Cffu completed with the value empty list.
*
* Same as [allOfCffuVoid], but the returned Cffu contains the results of input CompletableFutures.
* Same as [CffuFactory.cffuAllOf], providing this method is convenient for method chaining.
Expand All @@ -132,8 +129,7 @@ fun <T> Collection<CompletableFuture<T>>.allOfCffu(cffuFactory: CffuFactory): Cf
* the new Cffu is completed when all the given CompletableFutures complete.
* If any of the given CompletableFutures complete exceptionally, then the returned Cffu
* also does so, with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a Cffu completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a Cffu completed with the value empty list.
*
* Same as [allOfCffuVoid], but the returned Cffu contains the results of input CompletableFutures.
* Same as [CffuFactory.cffuAllOf], providing this method is convenient for method chaining.
Expand Down Expand Up @@ -228,8 +224,7 @@ fun Array<out CompletableFuture<*>>.allOfCffuVoid(cffuFactory: CffuFactory): Cff
* If any of the given Cffus complete exceptionally, then the returned Cffu
* also does so *without* waiting other incomplete given Cffus,
* with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a Cffu completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a Cffu completed with the value empty list.
*
* Same as [allOfFastFailCffuVoid], but the returned Cffu contains the results of input Cffus.
* Same as [CffuFactory.cffuAllOfFastFail], providing this method is convenient for method chaining.
Expand All @@ -252,8 +247,7 @@ fun <T> Collection<Cffu<T>>.allOfFastFailCffu(cffuFactory: CffuFactory = ABSENT)
* If any of the given Cffus complete exceptionally, then the returned Cffu
* also does so *without* waiting other incomplete given Cffus,
* with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a Cffu completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a Cffu completed with the value empty list.
*
* Same as [allOfFastFailCffuVoid], but the returned Cffu contains the results of input Cffus.
* Same as [CffuFactory.cffuAllOfFastFail], providing this method is convenient for method chaining.
Expand All @@ -276,8 +270,7 @@ fun <T> Array<Cffu<T>>.allOfFastFailCffu(cffuFactory: CffuFactory = ABSENT): Cff
* If any of the given CompletableFutures complete exceptionally, then the returned Cffu
* also does so *without* waiting other incomplete given CompletableFutures,
* with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a Cffu completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a Cffu completed with the value empty list.
*
* Same as [allOfFastFailCffuVoid], but the returned Cffu contains the results of input Cffus.
* Same as [CffuFactory.cffuAllOfFastFail], providing this method is convenient for method chaining.
Expand All @@ -295,8 +288,7 @@ fun <T> Collection<CompletableFuture<T>>.allOfFastFailCffu(cffuFactory: CffuFact
* If any of the given CompletableFutures complete exceptionally, then the returned Cffu
* also does so *without* waiting other incomplete given CompletableFutures,
* with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a Cffu completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a Cffu completed with the value empty list.
*
* Same as [allOfFastFailCffuVoid], but the returned Cffu contains the results of input Cffus.
* Same as [CffuFactory.cffuAllOfFastFail], providing this method is convenient for method chaining.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ import java.util.concurrent.TimeUnit
* CompletableFutures, the returned new CompletableFuture is completed when all the given CompletableFutures complete.
* If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture
* also does so, with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a CompletableFuture completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list.
*
* Same as [allOfCompletableFutureVoid],
* but the returned CompletableFuture contains the results of input CompletableFutures.
Expand All @@ -49,8 +48,7 @@ fun <T> Collection<CompletableFuture<T>>.allOfCompletableFuture(): CompletableFu
* CompletableFutures, the returned new CompletableFuture is completed when all the given CompletableFutures complete.
* If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture
* also does so, with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a CompletableFuture completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list.
*
* Same as [allOfCompletableFutureVoid],
* but the returned CompletableFuture contains the results of input CompletableFutures.
Expand Down Expand Up @@ -112,8 +110,7 @@ fun Array<out CompletableFuture<*>>.allOfCompletableFutureVoid(): CompletableFut
* If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture
* also does so *without* waiting other incomplete given CompletableFutures,
* with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a CompletableFuture completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list.
*
* Same as [allOfFastFailCompletableFutureVoid],
* but the returned CompletableFuture contains the results of input CompletableFutures.
Expand All @@ -131,8 +128,7 @@ fun <T> Collection<CompletableFuture<T>>.allOfFastFailCompletableFuture(): Compl
* If any of the given CompletableFutures complete exceptionally, then the returned CompletableFuture
* also does so *without* waiting other incomplete given CompletableFutures,
* with a CompletionException holding this exception as its cause.
* If no CompletableFutures are provided, returns a CompletableFuture completed
* with the value [emptyList][java.util.Collections.emptyList].
* If no CompletableFutures are provided, returns a CompletableFuture completed with the value empty list.
*
* Same as [allOfFastFailCompletableFutureVoid],
* but the returned CompletableFuture contains the results of input CompletableFutures.
Expand Down

0 comments on commit d9568ba

Please sign in to comment.