It is possible to have your cake and eat it too.
The Streams API in Java 8 doesn't handle exceptions or resources properly. Superior Streams are a wrapper around the JDK Streams API that adds proper exception passing and resource management without complicating the API.
New: Experimental Collections API replacement featuring regular and immutable versions of Map, Set and List. This is integrated to a new version of the Stream API.
Superior examples
Lambda expressions throwing IOExceptions are just as simple to use as those throwing unchecked exceptions:
//*/ static Object[] example1(IOStream<File> s3, Stream<File> s33) { IOFunction<File, JarFile> toJarFile1 = JarFile::new; IOStream<JarFile> s4 = s3.map(toJarFile1); // Using JDK Streams requires twisting and turning: Function<File, JarFile> toJarFile2 = (File file) -> { try { return new JarFile(file); } catch(IOException e) { throw new UncheckedIOException(e); } }; Stream<JarFile> s43 = s33.map(toJarFile2); return new Object[] {s4,s43}; }/*/
Resources are released as soon as they are no longer needed, automatically and transparently:
//*/ static void example2(Path install, Predicate<Path> isJdk) throws IOException { IOStream<Path> s1 = Files.list(install); IOStream<Path> s2 = s1.filter(isJdk); for(Path path : s1.iterable()) { System.out.println(path); } for(Path path : s2.iterable()) { System.out.println(path); } // JDK Streams need to be manually tracked at each use site: try(java.util.stream.Stream<Path> s11 = java.nio.file.Files.list(install); java.util.stream.Stream<Path> s12 = java.nio.file.Files.list(install);) { java.util.stream.Stream<Path> s22 = s12.filter(isJdk); for(Path path : (Iterable<Path>) () -> s11.iterator()) { System.out.println(path); } for(Path path : (Iterable<Path>) () -> s22.iterator()) { System.out.println(path); } } }/*/
Superior Streams can be freely reused as many times as needed:
//*/ static Object[] example3(List<String> JDK_PROJECTS1, java.util.List<String> JDK_PROJECTS2) { Stream<String> projects1 = JDK_PROJECTS1.stream(); Predicate<String> isPrefix1 = (String path) -> projects1.anyMatch(path::startsWith); // Each Stream from JDK can only be used once or the result is an exception at runtime: Supplier<java.util.stream.Stream<String>> projects2 = () -> JDK_PROJECTS2.stream(); Predicate<String> isPrefix2 = (String path) -> projects2.get().anyMatch(path::startsWith); return new Object[] {isPrefix1,isPrefix2}; }/*/
Extra Features
Replacements for standard library ArrayList, HashSet and HashMap collections
Mutable and immutable versions:
//*/ static Object[] example4() { ArrayList<String> list = new ArrayList<>(); HashSet<String> set = list.add("1").add("2").toHashSet(); // Immutable versions use the same API but return copies when changed: List<String> immutableList = list.toList(); Set<String> immutableSet = set.toSet().replaceAll(s -> "log: " + s); return new Object[] {immutableList,immutableSet}; }/*/
With exceptions passing through as expected:
//*/ static FileTime getLastModifiedTime(Path path) throws IOException { return lastModifiedCache.computeIfAbsent(path, p -> Files.getLastModifiedTime(path)).get(path); } private static HashMap<Path, FileTime> lastModifiedCache = new HashMap<>(); // Standard library version requires lots of catching and re-throwing: static FileTime getLastModifiedTime2(Path path) throws IOException { try { return lastModifiedCache2.computeIfAbsent(path, p -> { try { return Files.getLastModifiedTime(path); } catch(IOException e) { throw new UncheckedIOException(e); } }); } catch(UncheckedIOException e) { throw e.getCause(); } } private static java.util.Map<Path, FileTime> lastModifiedCache2 = new java.util.HashMap<>(); /*/
Streams of RGB pixels for image manipulation
Image manipulation using red, green, blue channels:
//*/ static void example6() throws IOException { RGBStream stream = Streams.loadImageInRGB("pagoda.jpg"); stream.swapRedAndGreen().save("pagoda_rg.jpg"); stream.swapRedAndBlue().save("pagoda_rb.jpg"); stream.swapAlphaAndBlue().save("pagoda_ab.png"); stream.setRed(255).save("pagoda_bright_red.png"); }/*/
Image color manipulation in HSB changing hue, saturation and brightness values:
//*/ static void example7() throws IOException { HSBStream hsb = Streams.loadImageInHSB("pagoda.jpg"); hsb.mapBrightness((h, s, b, a) -> b * 0.25).save("pagoda_dark.jpg"); hsb.mapHue((h, s, b, a) -> h + 60).save("pagoda_altered_hue.jpg"); }/*/
Gamma adjustments:
//*/ static void example8() throws IOException { RGBStream stream = Streams.loadImageInRGB("pagoda.jpg"); stream.gammaExpand(2.4).save("pagoda_texture.jpg"); HSBStream bw = stream.toBlackAndWhite(); bw.save("pagoda_bw.jpg"); bw.gammaCompress(0.5).save("pagoda_bw2.jpg"); }/*/
Helper methods for WHERE clauses over Lists, Maps and Sets
//*/ static ArrayList<String> removeBadWords(List<String> list) { return Streams.where(list, s -> s.contains("fuck") == false); }/*/
Superior Streams are still largely untested
Or rather, they are being gradually tested over time.
License
Your choice of:
Several collections classes in the utils.lists2 package are based on classes from gs-collections by Goldman Sachs and are licensed under the Apache License, Version 2.0.
The image pagoda.jpg, by the author plusgood, is licensed under the Creative Commons Attribution 2.0 Generic license. Downloaded from the Wikimedia Commons.
