diff --git a/src/main/java/stormpot/BSlot.java b/src/main/java/stormpot/BSlot.java index 2cb881da..66e0cda4 100644 --- a/src/main/java/stormpot/BSlot.java +++ b/src/main/java/stormpot/BSlot.java @@ -61,14 +61,13 @@ private int getClaimState() { } private PoolException badStateOnTransitionToLive(int slotState) { - String state; - switch (slotState) { - case DEAD: state = "DEAD"; break; - case LIVING: state = "LIVING"; break; - default: state = "STATE[" + slotState + "]"; - } + String state = switch (slotState) { + case DEAD -> "DEAD"; + case LIVING -> "LIVING"; + default -> "STATE[" + slotState + "]"; + }; return new PoolException("Slot release from bad state: " + state + ". " + - "You most likely called release() twice on the same object."); + "You most likely called release() twice on the same object."); } void claim2live() { diff --git a/src/main/java/stormpot/PoolBuilder.java b/src/main/java/stormpot/PoolBuilder.java index 3cc212cb..19156c35 100644 --- a/src/main/java/stormpot/PoolBuilder.java +++ b/src/main/java/stormpot/PoolBuilder.java @@ -109,7 +109,7 @@ DIRECT, new PoolBuilderPermissions(false, true, false, false, false) * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setSize(int size) { - checkPermission(permissions.setSize, "size"); + checkPermission(permissions.setSize(), "size"); if (size < 0) { throw new IllegalArgumentException("Size must be at least 0, but was " + size + "."); } @@ -143,7 +143,7 @@ public synchronized int getSize() { @SuppressWarnings("unchecked") public synchronized PoolBuilder setAllocator( Allocator allocator) { - checkPermission(permissions.setAllocator, "allocator"); + checkPermission(permissions.setAllocator(), "allocator"); requireNonNull(allocator, "The Allocator cannot be null."); this.allocator = (Allocator) allocator; return (PoolBuilder) this; @@ -184,7 +184,7 @@ public synchronized Reallocator getReallocator() { * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setExpiration(Expiration expiration) { - checkPermission(permissions.setExpiration, "expiration"); + checkPermission(permissions.setExpiration(), "expiration"); requireNonNull(expiration, "Expiration cannot be null."); this.expiration = expiration; return this; @@ -241,7 +241,7 @@ public synchronized ThreadFactory getThreadFactory() { * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setThreadFactory(ThreadFactory factory) { - checkPermission(permissions.setThreadFactory, "thread factory"); + checkPermission(permissions.setThreadFactory(), "thread factory"); requireNonNull(factory, "ThreadFactory cannot be null."); threadFactory = factory; return this; @@ -314,7 +314,7 @@ public synchronized boolean isBackgroundExpirationEnabled() { * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setBackgroundExpirationEnabled(boolean enabled) { - checkPermission(permissions.setBackgroundExpiration, "background expiration enabled/disabled"); + checkPermission(permissions.setBackgroundExpiration(), "background expiration enabled/disabled"); backgroundExpirationEnabled = enabled; return this; } @@ -347,7 +347,7 @@ public synchronized int getBackgroundExpirationCheckDelay() { * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setBackgroundExpirationCheckDelay(int delay) { - checkPermission(permissions.setBackgroundExpiration, "background expiration check delay"); + checkPermission(permissions.setBackgroundExpiration(), "background expiration check delay"); if (delay < 0) { throw new IllegalArgumentException("Background expiration check delay cannot be negative."); } @@ -362,7 +362,7 @@ public synchronized PoolBuilder setBackgroundExpirationCheckDelay(int delay) */ @SuppressWarnings("unchecked") @Override - public final synchronized PoolBuilder clone() { + public synchronized PoolBuilder clone() { try { return (PoolBuilder) super.clone(); } catch (CloneNotSupportedException e) { diff --git a/src/main/java/stormpot/PoolBuilderPermissions.java b/src/main/java/stormpot/PoolBuilderPermissions.java index b73eeabe..2a22aa06 100644 --- a/src/main/java/stormpot/PoolBuilderPermissions.java +++ b/src/main/java/stormpot/PoolBuilderPermissions.java @@ -15,23 +15,10 @@ */ package stormpot; -class PoolBuilderPermissions { - final boolean setAllocator; - final boolean setSize; - final boolean setExpiration; - final boolean setThreadFactory; - final boolean setBackgroundExpiration; - - PoolBuilderPermissions( - boolean setAllocator, - boolean setSize, - boolean setExpiration, - boolean setThreadFactory, - boolean setBackgroundExpiration) { - this.setAllocator = setAllocator; - this.setSize = setSize; - this.setExpiration = setExpiration; - this.setThreadFactory = setThreadFactory; - this.setBackgroundExpiration = setBackgroundExpiration; - } +record PoolBuilderPermissions( + boolean setAllocator, + boolean setSize, + boolean setExpiration, + boolean setThreadFactory, + boolean setBackgroundExpiration) { } diff --git a/src/main/java/stormpot/PoolException.java b/src/main/java/stormpot/PoolException.java index 8b0f6691..444e9e16 100644 --- a/src/main/java/stormpot/PoolException.java +++ b/src/main/java/stormpot/PoolException.java @@ -15,6 +15,8 @@ */ package stormpot; +import java.io.Serial; + /** * The PoolException may be thrown by a pool implementation in a number of * circumstances: @@ -32,6 +34,7 @@ * @author Chris Vest */ public class PoolException extends RuntimeException { + @Serial private static final long serialVersionUID = -1908093409167496640L; /** diff --git a/src/main/java/stormpot/PreciseLeakDetector.java b/src/main/java/stormpot/PreciseLeakDetector.java index 6a8ed5cd..22e295ca 100644 --- a/src/main/java/stormpot/PreciseLeakDetector.java +++ b/src/main/java/stormpot/PreciseLeakDetector.java @@ -43,7 +43,7 @@ private static class WeakRef extends WeakReference { // 'probe' array. When inserting, if that slot is null, then we insert the // WeakRef directly into that place. In fact, we allow building a WeakRef // chain up to 4 elements long, directly in the first-level 'probes' array. - // Otherwise we add the second-level 32 element array, rehash the existing + // Otherwise, we add the second-level 32 element array, rehash the existing // chain into it, by using the next 5 second-least significant bits as // index. From here on, we don't create any more levels, but just link the // WeakRefs together like a daisy-chain. This way, we create at most 33 @@ -62,8 +62,7 @@ synchronized void register(Object obj) { return; } - if (current instanceof WeakRef) { - WeakRef currentRef = (WeakRef) current; + if (current instanceof WeakRef currentRef) { if (chainShorterThan(4, current)) { WeakRef ref = new WeakRef(obj); ref.next = currentRef; @@ -120,8 +119,7 @@ synchronized void unregister(Object obj) { Object current = probes[hash1]; - if (current instanceof WeakRef) { - WeakRef ref = (WeakRef) current; + if (current instanceof WeakRef ref) { probes[hash1] = removeFromChain(ref, obj); return; } @@ -154,8 +152,7 @@ synchronized long countLeakedObjects() { Object current = probes[i]; if (current instanceof WeakRef) { probes[i] = pruneChain((WeakRef) current); - } else if (current instanceof WeakRef[]) { - WeakRef[] level2 = (WeakRef[]) current; + } else if (current instanceof WeakRef[] level2) { for (int j = 0; j < level2.length; j++) { level2[j] = pruneChain(level2[j]); } diff --git a/src/main/java/stormpot/Timeout.java b/src/main/java/stormpot/Timeout.java index 361d0da0..a6a8226f 100644 --- a/src/main/java/stormpot/Timeout.java +++ b/src/main/java/stormpot/Timeout.java @@ -142,7 +142,7 @@ public TimeUnit getBaseUnit() { @Override public int hashCode() { - return 31 * (1 + (int) (timeoutBase ^ (timeoutBase >>> 32))); + return 31 * (1 + Long.hashCode(timeoutBase)); } /** @@ -153,10 +153,9 @@ public int hashCode() { */ @Override public boolean equals(Object obj) { - if (!(obj instanceof Timeout)) { - return false; - } - Timeout that = (Timeout) obj; - return this.timeoutBase == that.timeoutBase; + if (obj instanceof Timeout that) { + return this.timeoutBase == that.timeoutBase; + } + return false; } } diff --git a/src/test/java/blackbox/AbstractPoolTest.java b/src/test/java/blackbox/AbstractPoolTest.java index 260f9070..5b620e95 100644 --- a/src/test/java/blackbox/AbstractPoolTest.java +++ b/src/test/java/blackbox/AbstractPoolTest.java @@ -39,7 +39,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -55,7 +54,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import static stormpot.UnitKit.$await; import static stormpot.UnitKit.$catchFrom; import static stormpot.UnitKit.$claim; @@ -123,11 +121,8 @@ void tryClaimMustReturnIfPoolIsNotEmpty(Taps taps) throws Exception { T a = tap.claim(longTimeout); // Wait for the pool to be populated a.release(); T obj = tap.tryClaim(); - try { - assertThat(obj).isNotNull(); - } finally { - obj.release(); - } + assertThat(obj).isNotNull(); + obj.release(); } /** @@ -158,11 +153,8 @@ void tryClaimMustReturnNullIfPoolIsEmpty(Taps taps) throws Exception { void claimMustReturnIfWithinTimeout(Taps taps) throws Exception { createOneObjectPool(); T obj = taps.get(this).claim(longTimeout); - try { - assertThat(obj).isNotNull(); - } finally { - obj.release(); - } + assertThat(obj).isNotNull(); + obj.release(); } /** @@ -1081,18 +1073,6 @@ void supplyMustReleaseClaimedObject(Taps taps) throws Exception { tap.supply(longTimeout, nullConsumer); } - private static Object expectException(Callable callable) { - try { - callable.call(); - fail("The ExpectedException was not thrown"); - } catch (ExpectedException ignore) { - // We expect this - } catch (Exception e) { - throw new AssertionError("Failed for other reason", e); - } - return null; - } - @ParameterizedTest @EnumSource(Taps.class) void applyMustReleaseClaimedObjectEvenIfFunctionThrows(Taps taps) throws Exception { @@ -1102,12 +1082,12 @@ void applyMustReleaseClaimedObjectEvenIfFunctionThrows(Taps taps) throws Excepti throw new ExpectedException(); }; - expectException(() -> tap.apply(longTimeout, thrower)); - expectException(() -> tap.apply(longTimeout, thrower)); - fork(() -> expectException(() -> tap.apply(longTimeout, thrower))).join(); - fork(() -> expectException(() -> tap.apply(longTimeout, thrower))).join(); - expectException(() -> tap.apply(longTimeout, thrower)); - expectException(() -> tap.apply(longTimeout, thrower)); + assertThrows(ExpectedException.class, () -> tap.apply(longTimeout, thrower)); + assertThrows(ExpectedException.class, () -> tap.apply(longTimeout, thrower)); + fork(() -> assertThrows(ExpectedException.class, () -> tap.apply(longTimeout, thrower))).join(); + fork(() -> assertThrows(ExpectedException.class, () -> tap.apply(longTimeout, thrower))).join(); + assertThrows(ExpectedException.class, () -> tap.apply(longTimeout, thrower)); + assertThrows(ExpectedException.class, () -> tap.apply(longTimeout, thrower)); } @ParameterizedTest @@ -1119,12 +1099,12 @@ void supplyMustReleaseClaimedObjectEvenIfConsumerThrows(Taps taps) throws Except throw new ExpectedException(); }; - expectException(() -> tap.supply(longTimeout, thrower)); - expectException(() -> tap.supply(longTimeout, thrower)); - fork(() -> expectException(() -> tap.supply(longTimeout, thrower))).join(); - fork(() -> expectException(() -> tap.supply(longTimeout, thrower))).join(); - expectException(() -> tap.supply(longTimeout, thrower)); - expectException(() -> tap.supply(longTimeout, thrower)); + assertThrows(ExpectedException.class, () -> tap.supply(longTimeout, thrower)); + assertThrows(ExpectedException.class, () -> tap.supply(longTimeout, thrower)); + fork(() -> assertThrows(ExpectedException.class, () -> tap.supply(longTimeout, thrower))).join(); + fork(() -> assertThrows(ExpectedException.class, () -> tap.supply(longTimeout, thrower))).join(); + assertThrows(ExpectedException.class, () -> tap.supply(longTimeout, thrower)); + assertThrows(ExpectedException.class, () -> tap.supply(longTimeout, thrower)); } @ParameterizedTest diff --git a/src/test/java/blackbox/AllocatorBasedPoolTest.java b/src/test/java/blackbox/AllocatorBasedPoolTest.java index bc38b862..63161ba3 100644 --- a/src/test/java/blackbox/AllocatorBasedPoolTest.java +++ b/src/test/java/blackbox/AllocatorBasedPoolTest.java @@ -737,7 +737,7 @@ void mustPropagateExceptionsFromAllocateThroughClaim(Taps taps) throws Exception tap.claim(longTimeout); fail("expected claim to throw"); } catch (PoolException poolException) { - assertThat(poolException.getCause()).isSameAs((Throwable) expectedException); + assertThat(poolException.getCause()).isSameAs(expectedException); } } @@ -774,7 +774,7 @@ void mustPropagateExceptionsFromReallocateThroughClaim(Taps taps) throws Excepti tap.claim(longTimeout); fail("expected claim to throw"); } catch (PoolException poolException) { - assertThat(poolException.getCause()).isSameAs((Throwable) expectedException); + assertThat(poolException.getCause()).isSameAs(expectedException); } } @@ -1215,7 +1215,7 @@ void decreasingSizeMustEventuallyDeallocateSurplusObjects(Taps taps) throws Exce pool.setTargetSize(newSize); while (allocator.countDeallocations() != startingSize - newSize) { if (!objs.isEmpty()) { - objs.remove(0).release(); // give the pool objects to deallocate + objs.removeFirst().release(); // give the pool objects to deallocate } else { tap.claim(longTimeout).release(); // prod it & poke it } @@ -1274,7 +1274,7 @@ void mustNotReallocateWhenReleasingExpiredObjectsIntoShrunkPool() pool.setTargetSize(newSize); for (int i = 0; i < startingSize - newSize; i++) { // release the surplus expired objects back into the pool - objs.remove(0).release(); + objs.removeFirst().release(); } // now the released objects should not cause reallocations, so claim // returns null (it's still depleted) and allocation count stays put @@ -1282,7 +1282,7 @@ void mustNotReallocateWhenReleasingExpiredObjectsIntoShrunkPool() assertThat(pool.claim(shortTimeout)).isNull(); assertThat(allocator.countAllocations()).isEqualTo(startingSize); } finally { - objs.remove(0).release(); + objs.removeFirst().release(); } } @@ -1860,7 +1860,7 @@ void newlyAllocatedObjectsMustBeClaimedAheadOfExistingLiveObjects(Taps taps) thr GenericPoolable a = tap.claim(longTimeout); try { List allocations = allocator.getAllocations(); - assertThat(a).isSameAs(allocations.get(allocations.size() - 1)); + assertThat(a).isSameAs(allocations.getLast()); } finally { a.release(); } diff --git a/src/test/java/blackbox/ThreadBasedPoolTest.java b/src/test/java/blackbox/ThreadBasedPoolTest.java index c78317ee..06f8b32c 100644 --- a/src/test/java/blackbox/ThreadBasedPoolTest.java +++ b/src/test/java/blackbox/ThreadBasedPoolTest.java @@ -170,11 +170,8 @@ void mustProactivelyReallocatePoisonedSlotsWhenAllocatorStopsThrowingExceptions( createPool(); allocationLatch.await(); GenericPoolable obj = pool.claim(longTimeout); - try { - assertThat(obj).isNotNull(); - } finally { - obj.release(); - } + assertThat(obj).isNotNull(); + obj.release(); } @Test @@ -196,11 +193,8 @@ void mustProactivelyReallocatePoisonedSlotsWhenReallocatorStopsThrowingException allocationLatch.await(); expired.set(false); obj = pool.claim(longTimeout); - try { - assertThat(obj).isNotNull(); - } finally { - obj.release(); - } + assertThat(obj).isNotNull(); + obj.release(); } @Test @@ -213,11 +207,8 @@ void mustProactivelyReallocatePoisonedSlotsWhenAllocatorStopsReturningNull() createPool(); allocationLatch.await(); GenericPoolable obj = pool.claim(longTimeout); - try { - assertThat(obj).isNotNull(); - } finally { - obj.release(); - } + assertThat(obj).isNotNull(); + obj.release(); } @Test @@ -242,11 +233,8 @@ void mustProactivelyReallocatePoisonedSlotsWhenReallocatorStopsReturningNull() allocationLatch.await(); expired.set(false); obj = pool.claim(longTimeout); - try { - assertThat(obj).isNotNull(); - } finally { - obj.release(); - } + assertThat(obj).isNotNull(); + obj.release(); } @Test @@ -326,10 +314,10 @@ void poolMustUseConfiguredThreadFactoryWhenCreatingBackgroundThreads() createPool(); pool.claim(longTimeout).release(); assertThat(createdThreads.size()).isEqualTo(1); - assertTrue(createdThreads.get(0).isAlive()); + assertTrue(createdThreads.getFirst().isAlive()); pool.shutdown().await(longTimeout); assertThat(createdThreads.size()).isEqualTo(1); - Thread thread = createdThreads.get(0); + Thread thread = createdThreads.getFirst(); thread.join(); assertFalse(thread.isAlive()); } @@ -457,7 +445,6 @@ void backgroundExpirationMustNotExpireObjectsThatAreClaimed(Taps taps) throws Ex List deallocations = allocator.getDeallocations(); // Synchronized to guard against concurrent modification from the allocator - //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (deallocations) { assertThat(deallocations).doesNotContain(obj); } diff --git a/src/test/java/blackbox/TimeoutTest.java b/src/test/java/blackbox/TimeoutTest.java index 574d4770..4a5543a7 100644 --- a/src/test/java/blackbox/TimeoutTest.java +++ b/src/test/java/blackbox/TimeoutTest.java @@ -81,6 +81,7 @@ void timeoutsAreNotEqualToNull() { assertFalse(a.equals(null)); } + @SuppressWarnings("EqualsWithItself") @Test void timeoutsAreEqualToThemselves() { Timeout a = new Timeout(1, TimeUnit.SECONDS); diff --git a/src/test/java/blackbox/simulations/Sim.java b/src/test/java/blackbox/simulations/Sim.java index a937697a..5f2610c9 100644 --- a/src/test/java/blackbox/simulations/Sim.java +++ b/src/test/java/blackbox/simulations/Sim.java @@ -123,14 +123,7 @@ protected enum Output { TimeUnit value() default TimeUnit.MILLISECONDS; } - private static class Link { - final Link tail; - final T value; - - private Link(Link tail, T value) { - this.tail = tail; - this.value = value; - } + private record Link(Sim.Link tail, T value) { } public static void main(String[] args) throws Exception { diff --git a/src/test/java/blackbox/slow/PoolIT.java b/src/test/java/blackbox/slow/PoolIT.java index e9ceab73..a625922a 100644 --- a/src/test/java/blackbox/slow/PoolIT.java +++ b/src/test/java/blackbox/slow/PoolIT.java @@ -96,7 +96,6 @@ void verifyObjectsAreNeverDeallocatedMoreThanOnce(TestInfo info) throws Interrup List deallocated = allocator.getDeallocations(); // Synchronize to avoid ConcurrentModification with background thread - //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (deallocated) { deallocated.sort(Comparator.comparingInt(System::identityHashCode)); Iterator iter = deallocated.iterator(); diff --git a/src/test/java/extensions/ExecutorExtension.java b/src/test/java/extensions/ExecutorExtension.java index 7305559e..d227f6cf 100644 --- a/src/test/java/extensions/ExecutorExtension.java +++ b/src/test/java/extensions/ExecutorExtension.java @@ -91,6 +91,7 @@ public void printOnFailure(Future future) { futuresToPrintOnFailure.add(future); } + @SuppressWarnings("CallToPrintStackTrace") private void printFuturesForFailure() { System.err.println( "\n===[ Dumping all registered futures ]===\n"); diff --git a/src/test/java/extensions/FailurePrinterExtension.java b/src/test/java/extensions/FailurePrinterExtension.java index c7810f84..0e7051a8 100644 --- a/src/test/java/extensions/FailurePrinterExtension.java +++ b/src/test/java/extensions/FailurePrinterExtension.java @@ -32,13 +32,13 @@ /** * An Extension that ensures that any failing tests have their stack-trace * printed to stderr. - * + *

* This is useful for when the tests are running on a build-server, and you'd * like the details of any failure to be printed to the build-log. A nice thing * if the build system does not make the build artifacts with the test failures * available. * - * @author cvh + * @author Chris Vest */ public class FailurePrinterExtension implements Extension, BeforeEachCallback, AfterEachCallback { private ThreadMXBean threadMXBean; @@ -73,6 +73,7 @@ public void beforeEach(ExtensionContext context) { cores = operatingSystemMXBean.getAvailableProcessors(); } + @SuppressWarnings("CallToPrintStackTrace") @Override public void afterEach(ExtensionContext context) { Optional executionException = context.getExecutionException(); diff --git a/src/test/java/stormpot/ExpectedException.java b/src/test/java/stormpot/ExpectedException.java index 8e944769..2b0f257e 100644 --- a/src/test/java/stormpot/ExpectedException.java +++ b/src/test/java/stormpot/ExpectedException.java @@ -15,6 +15,9 @@ */ package stormpot; +import java.io.Serial; + public class ExpectedException extends RuntimeException { + @Serial private static final long serialVersionUID = -7222172301643374026L; } diff --git a/src/test/java/stormpot/SomeRandomException.java b/src/test/java/stormpot/SomeRandomException.java index d277224d..44bfc249 100644 --- a/src/test/java/stormpot/SomeRandomException.java +++ b/src/test/java/stormpot/SomeRandomException.java @@ -15,11 +15,14 @@ */ package stormpot; +import java.io.Serial; + /** * Thrown by tests to assert that exceptions bubble out when they should. * @author Chris Vest <mr.chrisvest@gmail.com> * */ public class SomeRandomException extends Exception { + @Serial private static final long serialVersionUID = 1L; } diff --git a/src/test/java/stormpot/SomeRandomThrowable.java b/src/test/java/stormpot/SomeRandomThrowable.java index 06c4dd9d..846a0325 100644 --- a/src/test/java/stormpot/SomeRandomThrowable.java +++ b/src/test/java/stormpot/SomeRandomThrowable.java @@ -15,7 +15,10 @@ */ package stormpot; +import java.io.Serial; + public class SomeRandomThrowable extends Throwable { + @Serial private static final long serialVersionUID = 42L; public SomeRandomThrowable(String message) { diff --git a/src/test/java/stormpot/UnitKit.java b/src/test/java/stormpot/UnitKit.java index 6859ed95..e55203dc 100644 --- a/src/test/java/stormpot/UnitKit.java +++ b/src/test/java/stormpot/UnitKit.java @@ -15,6 +15,7 @@ */ package stormpot; +import java.io.Serial; import java.lang.Thread.State; import java.util.ArrayList; import java.util.Arrays; @@ -52,6 +53,7 @@ private static Runnable asRunnable(final Callable procedure) { } private static class WrappedException extends RuntimeException { + @Serial private static final long serialVersionUID = 8268471823070464895L; WrappedException(Throwable cause) { @@ -63,6 +65,7 @@ private static class CatchingExceptionHandler extends AtomicReference implements Thread.UncaughtExceptionHandler { + @Serial private static final long serialVersionUID = 2170391393239672337L; @Override @@ -163,7 +166,7 @@ public static Callable capture( try { while (!list.isEmpty()) { delayUnit.sleep(delay); - list.remove(0).release(); + list.removeFirst().release(); } } catch (InterruptedException e) { for (Poolable obj : list) { @@ -198,9 +201,7 @@ public static void join(Thread thread) throws ExecutionException { thread.join(); Thread.UncaughtExceptionHandler handler = thread.getUncaughtExceptionHandler(); - if (handler instanceof CatchingExceptionHandler) { - CatchingExceptionHandler catchingHandler = - (CatchingExceptionHandler) handler; + if (handler instanceof CatchingExceptionHandler catchingHandler) { Throwable th = catchingHandler.get(); if (th != null) { throw new ExecutionException(th);