j.doe
j.doe

Reputation: 87

Generic function stream.map

I currently have a class test which transforms a stream to a stream of same type.

class Test {
    private Function<A1, A1> a1Transform;
    private Function<A2, A2> a2Transform;

    public <T extends A> Stream<T> transform(Stream<T> input) {
        return input
            .filter(o -> o instanceof A1)
            .map(A1.class::cast)
            .map(a1Transform);
    }
}

The code doesn't compile unless

  1. I make the return type Stream<? super T> or
  2. I add a .map(o -> (T) o) to cast it back to T.

Is either of the solutions any good. What would be a better way to approach this problem.

Upvotes: 1

Views: 1264

Answers (1)

Radiodef
Radiodef

Reputation: 37845

If A1, A2, etc. have a common supertype A, then you could change the method to something like the following:

public Stream<A> transform(Stream<?> input) {
    return input.filter(o -> o instanceof A1)
                .map(o -> (A1) o)
                .map(a1Transform)
                .map(o -> (A) o);
}

There's no way for a method to return, say, either Stream<A1>, or Stream<A2>, or Stream<A3>, etc. The best you can do is like the above, where you return a Stream<A>, or you could return a Stream<? extends A>.

If it's really important to return a stream with the exact type of the elements, then you could use something like the visitor pattern, and pass the visitor in to the method instead of returning the stream directly.

Another possible way could be for the caller to pass a Class in to the method:

public <T extends A> Stream<T> transform(Stream<?> input, Class<T> type) {
    return input...
                ...
                ...
                .map(type::cast);
}

However, running in to this kind of problem is usually an indication that you need to redesign something. In general, in object-oriented design, code which is external to your API should not be concerned with having specific types of objects.

Upvotes: 1

Related Questions