javaclasslambdajava-streamtimeoutexception

java.util.concurrent.TimeoutException Error


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:

  1. The string must contain the given pattern.
  2. The string's length must be equal or greater than minLength.
  3. The string's length must be an even or an odd number according to the given flag 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)

Solution

  • 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());
    }