diff --git a/src/org/openstreetmap/josm/tools/StreamUtils.java b/src/org/openstreetmap/josm/tools/StreamUtils.java
index 8f39c48..782bd9c 100644
--- a/src/org/openstreetmap/josm/tools/StreamUtils.java
+++ b/src/org/openstreetmap/josm/tools/StreamUtils.java
@@ -1,9 +1,7 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.tools;
 
-import java.util.Iterator;
-import java.util.Spliterator;
-import java.util.Spliterators;
+import java.util.Collection;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
@@ -20,13 +18,27 @@
     private StreamUtils() {}
 
     /**
-     * Convert an iterator to a stream.
-     * @param <T> The element type to iterate over
-     * @param iterator The iterator
-     * @return The stream of for that iterator.
+     * Returns a sequential {@code Stream} with the iterable as its source.
+     *
+     * @param <T>      The element type to iterate over
+     * @param iterable The iterable
+     * @return The stream of for that iterable.
+     * @see Collection#stream()
      */
-    public static <T> Stream<T> toStream(Iterator<? extends T> iterator) {
-        Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED);
-        return StreamSupport.stream(spliterator, false);
+    public static <T> Stream<T> toStream(Iterable<T> iterable) {
+        return StreamSupport.stream(iterable.spliterator(), false);
+    }
+
+    /**
+     * Filter an iterable by (sub)class.
+     *
+     * @param <S> Super type of items
+     * @param <T> type of items
+     * @param iterable the iterable to filter
+     * @param clazz the (sub)class
+     * @return a stream of (sub)class elements
+     */
+    public static <S, T extends S> Stream<T> filter(Iterable<S> iterable, Class<T> clazz) {
+        return StreamUtils.toStream(iterable).filter(clazz::isInstance).map(clazz::cast);
     }
 }
diff --git a/src/org/openstreetmap/josm/tools/Utils.java b/src/org/openstreetmap/josm/tools/Utils.java
index 277caf5..3499b5d 100644
--- a/src/org/openstreetmap/josm/tools/Utils.java
+++ b/src/org/openstreetmap/josm/tools/Utils.java
@@ -44,6 +44,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.StringJoiner;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.ForkJoinWorkerThread;
@@ -51,6 +52,8 @@
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.ZipEntry;
@@ -106,14 +109,12 @@ private Utils() {
      * @param collection the collection
      * @param predicate the predicate
      * @return {@code true} if {@code predicate} applies to at least one element from {@code collection}
+     * @deprecated Use {@link Stream#anyMatch} instead.
      */
+    @Deprecated
     public static <T> boolean exists(Iterable<? extends T> collection, Predicate<? super T> predicate) {
-        for (T item : collection) {
-            if (predicate.evaluate(item)) {
-                return true;
-            }
-        }
-        return false;
+        return StreamUtils.toStream(collection)
+                .anyMatch(predicate);
     }
 
     /**
@@ -124,9 +125,12 @@ private Utils() {
      * @param collection the collection
      * @param predicate the predicate
      * @return {@code true} if {@code predicate} applies to all elements from {@code collection}
+     * @deprecated Use {@link Stream#allMatch} instead.
      */
+    @Deprecated
     public static <T> boolean forAll(Iterable<? extends T> collection, Predicate<? super T> predicate) {
-        return !exists(collection, Predicates.not(predicate));
+        return StreamUtils.toStream(collection)
+                .allMatch(predicate);
     }
 
     /**
@@ -135,9 +139,12 @@ private Utils() {
      * @param collection The collection
      * @param clazz The class to search for.
      * @return <code>true</code> if that item exists in the collection.
+     * @deprecated Use {@link Stream#anyMatch} instead.
      */
+    @Deprecated
     public static <T> boolean exists(Iterable<T> collection, Class<? extends T> clazz) {
-        return exists(collection, Predicates.<T>isInstanceOf(clazz));
+        return StreamUtils.toStream(collection)
+                .anyMatch(clazz::isInstance);
     }
 
     /**
@@ -146,14 +153,14 @@ private Utils() {
      * @param collection The iterable to search in.
      * @param predicate The predicate to match
      * @return the item or <code>null</code> if there was not match.
+     * @deprecated Use {@code stream}{@link Stream#filter .filter(...)}{@link Stream#findFirst ,findFirst()} instead.
      */
+    @Deprecated
     public static <T> T find(Iterable<? extends T> collection, Predicate<? super T> predicate) {
-        for (T item : collection) {
-            if (predicate.evaluate(item)) {
-                return item;
-            }
-        }
-        return null;
+        return StreamUtils.toStream(collection)
+                .filter(predicate)
+                .findFirst()
+                .orElse(null);
     }
 
     /**
@@ -191,12 +198,10 @@ private Utils() {
      */
     @SafeVarargs
     public static <T> T firstNonNull(T... items) {
-        for (T i : items) {
-            if (i != null) {
-                return i;
-            }
-        }
-        return null;
+        return Stream.of(items)
+                .filter(Objects::nonNull)
+                .findFirst()
+                .orElse(null);
     }
 
     /**
@@ -301,23 +306,13 @@ public static int mod(int a, int n) {
      * @param values collection of objects, null is converted to the
      *  empty string
      * @return null if values is null. The joined string otherwise.
+     * @deprecated Use {@link String#join} or {@link Collectors#joining} instead.
      */
+    @Deprecated
     public static String join(String sep, Collection<?> values) {
-        CheckParameterUtil.ensureParameterNotNull(sep, "sep");
-        if (values == null)
-            return null;
-        StringBuilder s = null;
-        for (Object a : values) {
-            if (a == null) {
-                a = "";
-            }
-            if (s != null) {
-                s.append(sep).append(a);
-            } else {
-                s = new StringBuilder(a.toString());
-            }
-        }
-        return s != null ? s.toString() : "";
+        return values.stream()
+                .map(Objects::toString)
+                .collect(Collectors.joining(sep));
     }
 
     /**
@@ -326,13 +321,12 @@ public static String join(String sep, Collection<?> values) {
      * @return An unordered HTML list
      */
     public static String joinAsHtmlUnorderedList(Iterable<?> values) {
-        StringBuilder sb = new StringBuilder(1024);
-        sb.append("<ul>");
-        for (Object i : values) {
-            sb.append("<li>").append(i).append("</li>");
-        }
-        sb.append("</ul>");
-        return sb.toString();
+        return StreamUtils.toStream(values)
+                .map(Objects::toString)
+                .collect(Collector.of(
+                        () -> new StringJoiner("</li><li>", "<ul><li>", "</li></ul>").setEmptyValue("<ul></ul>"),
+                        StringJoiner::add, StringJoiner::merge, StringJoiner::toString
+                ));
     }
 
     /**
diff --git a/src/org/openstreetmap/josm/tools/bugreport/ReportedException.java b/src/org/openstreetmap/josm/tools/bugreport/ReportedException.java
index 434ca68..22efa08 100644
--- a/src/org/openstreetmap/josm/tools/bugreport/ReportedException.java
+++ b/src/org/openstreetmap/josm/tools/bugreport/ReportedException.java
@@ -256,7 +256,7 @@ public String toString() {
      * @since 10585
      */
     public boolean mayHaveConcurrentSource() {
-        return StreamUtils.toStream(new CauseTraceIterator())
+        return StreamUtils.toStream(CauseTraceIterator::new)
                 .anyMatch(t -> t instanceof ConcurrentModificationException || t instanceof InvocationTargetException);
     }
 
diff --git a/test/unit/org/openstreetmap/josm/tools/UtilsTest.java b/test/unit/org/openstreetmap/josm/tools/UtilsTest.java
index cbe2b8b..89bec7a 100644
--- a/test/unit/org/openstreetmap/josm/tools/UtilsTest.java
+++ b/test/unit/org/openstreetmap/josm/tools/UtilsTest.java
@@ -192,4 +192,15 @@ public void testSizeStringNegative() throws Exception {
         Utils.getSizeString(-1, Locale.ENGLISH);
     }
 
+    /**
+     * Test of {@link Utils#joinAsHtmlUnorderedList(Iterable)} method.
+     */
+    @Test
+    public void testJoinAsHtmlUnorderedList() {
+        assertEquals("<ul></ul>", Utils.joinAsHtmlUnorderedList(Arrays.asList()));
+        assertEquals("<ul><li>one</li></ul>", Utils.joinAsHtmlUnorderedList(Arrays.asList("one")));
+        assertEquals("<ul><li>one</li><li>two</li></ul>", Utils.joinAsHtmlUnorderedList(Arrays.asList("one", "two")));
+        assertEquals("<ul><li>one</li><li>two</li><li>many</li></ul>", Utils.joinAsHtmlUnorderedList(Arrays.asList("one", "two", "many")));
+    }
+
 }
