Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Consuming Java streams in Clojure

Java 8 brought the Stream interface, and with it convenient map/filter/reduce operations on Java collections (and other things that can be turned into a stream).

I find streams awkward and verbose to use from Clojure when interoperating with Java APIs that produce them.

Compare – Java:

Pattern.compile("\\s+").splitAsStream("one two three")
        .filter(s -> !s.contains("o"))
        .map(String::toUpperCase)
        .findFirst()
        .orElse(null);  // => "THREE"

Clojure, trying to use the same API:

(.. (.splitAsStream #"\s+" "one two three")
    (filter
      (reify java.util.function.Predicate
        (test [this value] (not (.contains value "o")))))
    (map
      (reify java.util.function.Function
        (apply [this value] (.toUpperCase value))))
    (findFirst)
    (orElse nil))  ; => "THREE"

Is there a better approach to consuming stream-based Java APIs in Clojure? Is it possible to turn a stream into a seq and use Clojure’s own transformation functions, like remove, partition, take?

like image 327
glts Avatar asked Feb 23 '16 09:02

glts


1 Answers

You can get a java.util.Iterator from the Stream using its iterator() method. That can be made a clojure sequence using iterator-seq:

(-> stream
    .iterator
    iterator-seq)
like image 187
Matthias Wimmer Avatar answered Nov 12 '22 01:11

Matthias Wimmer