2

I have a function with an Object as parameter. This object may be a collection in the most generic sense possible: it can be a list, a map, iterable, etc., in which case I want to process each item belonging to it:

public void f(Object o) {
    if (o instanceof SOMECLASSORINTERFACE<?>) {
        Stream.of(o).map( .. )...;
    } else {
        // o is scalar
        ...
    }
}

The code above doesn't work: Stream.of() doesn't split my object into its elements to stream, but only outputs one element, the object o itself.

I cannot use o.stream().map... because o is too generic and may not have the stream method.

Casting o to Collection does not work. Also, checking for Collection membership is probably not the right thing to do...

So how do I obtain a stream out of a generic collection?

Alexis C.
  • 91,686
  • 21
  • 171
  • 177
sebnukem
  • 8,143
  • 6
  • 38
  • 48

3 Answers3

3

The right thing would surely be not to have a function which takes an Object, but to use function oberloading and think of what you possibly could take:

  • Collection<T> – this indeed has a .stream() and covers most cases, such as List, Set etc.
  • Map<K,V> is not covered by Collection<T>, but its .entrySet(), .keySet() etc. would be.
  • Iterable<T> would have to be treated separately with StreamSupport.stream(((Iterable<?>) o).spliterator(), false) as you already mentionned.

So create three functions for the three cases above and you'll probably be fine:

public <T> void f(Stream<T> s) {
    s.map( .. )
        .forEach(System.out::println);
}

public void f(Collection<?> o) {
    f(o.stream());
}

public void f(Map<?,?> m) {
    f(m.entrySet().stream());
}

public void f(Iterable<?> i) {
    f(StreamSupport.stream(i.spliterator(), false));
}

public void f(Object o) {
    // for the cases none of the others match
    System.out.println(o);
}
glglgl
  • 89,107
  • 13
  • 149
  • 217
1

The solution I currently have is to test for both Iterable (see Convert Iterable to Stream using Java 8 JDK) and Map membership:

public void f(Object o) {
    if (o instanceof Iterable<?>) {
        StreamSupport.stream(((Iterable<?>) o).spliterator(), false).map(e -> ...
    } else if (o instanceof Map<?,?>) {
        ((Map<?,?>) o).entrySet().stream().map(e -> ... 
    } else {
        // scalar object
       ...
    }
}
Community
  • 1
  • 1
sebnukem
  • 8,143
  • 6
  • 38
  • 48
1

If your Object is a Collection<?> and you want to treat it like a Collection<?>, then cast it.

public void f(Object o) {
    if (o instanceof Collection<?>) {
        Collection<?> c = (Collection<?>)o;
        c.stream().map(...).forEach(System.out::println);
    } else {
        System.out.println(o);
    }
}
bradimus
  • 2,472
  • 1
  • 16
  • 23