I am trying to define a method that receives a stream of strings, and returns a sorted list where each string meets the following criteria:
minLength
.even
.Although I'm able to compile my code, I get a java.util.concurrent.TimeoutException
when running it.
Below is my method:
public static List<String> findWinners(String pattern, int minLength, boolean even, Stream<String> stream) {
return stream
.filter(x -> x.matches(pattern) && x.length() >= minLength)
.filter(x -> x.length() % 2 == (even ? 0 : 1))
.sorted(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}).collect(Collectors.toList());
}
Below is the full stack trace:
java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204)
at homeworkTests.StreamsHomeWorkTest.findWinners(StreamsHomeWorkTest.java:227)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)
at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.lang.Thread.run(Thread.java:829)
Based on the stack trace you've shared, the TimeoutException
has been thrown from the get
method of a FutureTask
. Specifically, the overloaded form that accepts a timeout, since the version with no parameters does not throw a TimeoutException
.
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204)
The problem in your code does not lie within your stream, but in the timeout passed to the get()
method, either because the value is too small or because the computation takes too long.
In general, when an upper time limit is not guaranteed, it is recommended to use the get()
form with no parameters, as this version of the method blocks the execution until completion or interruption via the corresponding exception.
As a side note, do not define a Comparator
for Integer
. Since Java 8, the Comparator
interface provides the method naturalOrder()
, which returns a Comparator
out of the box to compare Comparable
elements according to their natural order.
Furthermore, defining the order between elements by subtraction is error-prone, as the operation may overflow. This is not the case in your situation, since you're comparing lengths, therefore values between 0
and Integer.MAX_VALUE
. However, this is something you should keep in mind when defining a comparison logic.
Your stream could be re-written like this:
public static List<String> findWinners(String pattern, int minLength, boolean even, Stream<String> stream) {
return stream
.filter(x -> x.matches(pattern) && x.length() >= minLength && x.length() % 2 == (even ? 0 : 1))
.sorted(Comparator.naturalOrder())
.collect(Collectors.toList());
}