├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── build.gradle ├── collections ├── .gitignore ├── build.gradle ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ ├── solid │ │ ├── collections │ │ │ ├── SolidListTest.java │ │ │ ├── SolidMapTest.java │ │ │ └── SolidSetTest.java │ │ └── collectors │ │ │ ├── ToSolidListTest.java │ │ │ ├── ToSolidMapTest.java │ │ │ ├── ToSolidSetTest.java │ │ │ └── ToSparseArrayTest.java │ │ └── testkit │ │ ├── AssertIterableEquals.java │ │ └── ParcelFn.java │ └── main │ ├── AndroidManifest.xml │ └── java │ └── solid │ ├── collections │ ├── SolidList.java │ ├── SolidMap.java │ └── SolidSet.java │ └── collectors │ ├── ToSolidList.java │ ├── ToSolidMap.java │ ├── ToSolidSet.java │ └── ToSparseArray.java ├── gradle.properties ├── gradle ├── gradle-mvn-push.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── java7test ├── .gitignore ├── build.gradle └── src │ ├── main │ └── AndroidManifest.xml │ └── test │ └── java │ ├── solid │ └── stream │ │ └── StreamDemo.java │ └── test_utils │ └── AssertIterableEquals.java ├── retrolambdatest ├── .gitignore ├── build.gradle └── src │ ├── main │ └── AndroidManifest.xml │ └── test │ └── java │ ├── solid │ └── stream │ │ └── StreamDemo.java │ └── test_utils │ └── AssertIterableEquals.java ├── settings.gradle └── streams ├── .gitignore ├── build.gradle ├── gradle.properties └── src ├── main ├── AndroidManifest.xml └── java │ └── solid │ ├── collections │ ├── Grouped.java │ ├── Indexed.java │ └── Pair.java │ ├── collectors │ ├── ToArray.java │ ├── ToArrayList.java │ ├── ToArrays.java │ ├── ToJoinedString.java │ └── ToList.java │ ├── functions │ ├── Action0.java │ ├── Action1.java │ ├── Action2.java │ ├── Func0.java │ ├── Func1.java │ └── Func2.java │ ├── optional │ └── Optional.java │ └── stream │ ├── FixedSizeStream.java │ ├── Primitives.java │ ├── Range.java │ ├── ReadOnlyIterator.java │ └── Stream.java └── test └── java ├── solid ├── collectors │ └── ToArrayTest.java ├── converters │ ├── ToArrayListTest.java │ ├── ToArraysTest.java │ ├── ToJoinedStringTest.java │ └── ToListTest.java ├── optional │ └── OptionalTest.java └── stream │ ├── FixedSizeStreamTest.java │ ├── PrimitivesTest.java │ ├── RangeTest.java │ ├── ReadOnlyIteratorTest.java │ └── StreamTest.java └── test_utils └── AssertIterableEquals.java /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | .idea 4 | .DS_Store 5 | /build 6 | *.iml 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | env: 7 | global: 8 | - ADB_INSTALL_TIMEOUT=8 # default is 2 minutes and sometimes is not enough 9 | - ANDROID_ABI=armeabi-v7a # x86 is not supported yet :( 10 | - BUILD_TOOLS_VERSION=23.0.2 11 | - COMPILE_SDK_VERSION=22 12 | matrix: 13 | - ANDROID_TARGET_VERSION=15 14 | - ANDROID_TARGET_VERSION=16 15 | - ANDROID_TARGET_VERSION=19 16 | - ANDROID_TARGET_VERSION=21 17 | - ANDROID_TARGET_VERSION=22 18 | 19 | android: 20 | components: 21 | - platform-tools 22 | - tools 23 | 24 | - build-tools-$BUILD_TOOLS_VERSION 25 | 26 | - android-$COMPILE_SDK_VERSION 27 | - android-23 # for java7test 28 | 29 | - extra-android-m2repository 30 | 31 | - sys-img-$ANDROID_ABI-android-$ANDROID_TARGET_VERSION 32 | 33 | # Emulator Management: Create, Start and Wait 34 | before_script: 35 | # reply 'no' to 'Create custom emulator configuration?' 36 | - echo no | android create avd --force --name test --target "android-$ANDROID_TARGET_VERSION" --abi $ANDROID_ABI 37 | - emulator -avd test -no-skin -no-audio -no-window & 38 | - android-wait-for-emulator 39 | # unlock screen: 40 | - adb shell input keyevent 82 41 | 42 | script: 43 | - ./gradlew connectedAndroidTest 44 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ##### 3.0.1. version (31.08.2016) 4 | 5 | * SolidSet, SolidMap equals improvement. 6 | * Stream.zipWith operator. 7 | 8 | ##### 3.0.0 version (18.05.2016) 9 | 10 | * More flexible template functions declarations. 11 | 12 | ##### 2.0.3 version (02.04.2016) 13 | 14 | * `Stream.every`, `Stream.any` operators. 15 | 16 | ##### 2.0.2 version (26.12.2015) 17 | 18 | * `SolidList.list`, `SolidMap.map`, `SolidSet.set` construction methods. 19 | 20 | ##### 2.0.1 version (07.12.2015) 21 | 22 | * `Optional.map` operator. 23 | * `toArray()` collector. 24 | 25 | ##### 2.0.0 version (04.12.2015) 26 | 27 | * a complete library rework 28 | 29 | ##### 1.0.14 version (14.11.2015) 30 | 31 | * `accumulate` operator. 32 | * `ToSolidMap` deprecation. 33 | 34 | ##### 1.0.13 version (04.10.2015) 35 | 36 | * `reduce`, `fold` operators. 37 | 38 | ##### 1.0.12 version (03.10.2015) 39 | 40 | * `Group` operator. 41 | * `SolidEntry` object. 42 | * Collections guarantee item order now. 43 | * `toSolidMapByKey` converter. 44 | * The experimental stuff has been removed. 45 | * 100% line coverage with tests. 46 | 47 | ##### 1.0.11 version (26.08.2015) 48 | 49 | * `SolidSet`, `ToSolidSet`. 50 | 51 | ##### 1.0.10 version (17.08.2015) 52 | 53 | * `Stream.of(...)` - constructs a stream of given items. 54 | * `Stream.separate(...)` - removes a given set of items from a stream. 55 | 56 | ##### 1.0.9 version (05.08.2015) 57 | 58 | * `SolidMap`. - immutable, parcelable map. 59 | * `first()`, `last()` operators. 60 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Konstantin Mikheev sirstripy-at-gmail-com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Solid 2 | ===== 3 | 4 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Solid-green.svg?style=flat)](https://android-arsenal.com/details/1/1955) 5 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/info.android15.solid/streams/badge.png)](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22info.android15.solid%22%20AND%20a%3A%22streams%22) 6 | [![Build Status](https://travis-ci.org/konmik/solid.svg?branch=master)](https://travis-ci.org/konmik/solid) 7 | 8 | Solid is an Android library for data handling. 9 | 10 | It provides: 11 | 12 | * Lightweight and composable **data streams** with `Optional` implementation. 13 | 14 | * Primitive array / wrapped array **converters**. 15 | 16 | * `SolidList`, `SolidMap`, `SolidSet` - immutable, parcelable **collections**. 17 | 18 | ### Philosophy 19 | 20 | *Solid* library adheres to the philosophy: "transform it as a stream, keep it as immutable". 21 | Thus allowing to pass collections around without a fear that they can be changed by another part 22 | of the application, while keeping the ability to transform data in a convenient way. 23 | 24 | ### Include 25 | 26 | ``` groovy 27 | dependencies { 28 | def solidVersion = '2.0.3' 29 | compile "info.android15.solid:streams:$solidVersion" 30 | compile "info.android15.solid:collections:$solidVersion" 31 | } 32 | ``` 33 | 34 | Latest version: [![Maven Central](https://maven-badges.herokuapp.com/maven-central/info.android15.solid/streams/badge.png)](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22info.android15.solid%22%20AND%20a%3A%22streams%22) 35 | 36 | # Lightweight data streams 37 | 38 | *Solid* streams are similar to Java 8 streams but they are released under the MIT license and are absolutely free. 39 | 40 | These streams are passive and do not emit items, they are not thread-safe, so they are much simpler. 41 | 42 | All Solid streams are sequential. 43 | 44 | ### How to use 45 | 46 | All examples here with Java 8 syntax on. I recommend using [Gradle Retrolambda Plugin](https://github.com/evant/gradle-retrolambda) 47 | to make your code shorter. 48 | 49 | You can take any `Iterable` or an array and turn it into a set of chained methods: 50 | 51 | ``` java 52 | stream(asList(1, 3, 2)) // Iterable 53 | .filter(it -> it < 3) // only 1 and 2 items are not filtered 54 | .map(it -> Integer.toString(it)) // convert Integer values to String values 55 | .collect(toList()); 56 | ``` 57 | 58 | This code will result in a `List` which contains `"1"` and `"2"` values. 59 | 60 | Another example: we need to sort some items by name and then return their ids in a `SolidList`. 61 | 62 | ``` java 63 | stream(namedEntities) 64 | .sort((left, right) -> left.name.compareTo(right.name)) 65 | .map(it -> it.id) 66 | .collect(toSolidList()); 67 | ``` 68 | 69 | Easy, isn't it? I believe you already know about the power of streaming operators, 70 | so here is a very lightweight and convenient implementation, especially for needs of an Android developer. 71 | 72 | For a list of stream operators see: 73 | [Solid streams by example](https://github.com/konmik/solid/wiki/Solid-streams-by-example) 74 | 75 | # Data converters and primitive arrays 76 | 77 | Here is how converters look like: 78 | 79 | ``` java 80 | int[] values = of(1, 2, 3) // Iterable at this point 81 | .collect(toInts()) // int[] 82 | ``` 83 | 84 | Currently Solid supports conversion of these primitive types: `byte`, `double`, `float`, `int`, `long`. 85 | 86 | You can write your own converters if you wish - just implement a converting function and pass it into `Stream.collect()`. 87 | 88 | *Solid* converters are quite powerful: 89 | 90 | To convert a primitive array into an iterable stream just call one method. 91 | Call two methods to convert them into an immutable parcelable list. 92 | 93 | ``` java 94 | SolidList list = box(new byte[]{1, 2, 3}) 95 | .collect(toSolidList()); 96 | ``` 97 | 98 | Easy. 99 | 100 | Want to join two primitive arrays? 101 | 102 | ``` java 103 | byte[] joined = box(new byte[]{1, 2, 3}) 104 | .merge(box(new byte[]{4, 5, 6})) 105 | .collect(toBytes()); 106 | ``` 107 | 108 | Remove a value from a primitive array? 109 | 110 | ``` java 111 | byte[] array_1_3 = box(new byte[]{1, 2, 3}) 112 | .separate((byte) 2) 113 | .collect(toBytes()); 114 | ``` 115 | 116 | And so on. The amount of flexibility that iterable streams and converters provide is hard to get at the 117 | beginning but as long as you use them, more and more ideas come into mind. 118 | 119 | The full list of possible primitive converters is here: 120 | [ToArrays](https://github.com/konmik/solid/blob/master/streams/src/main/java/solid/collectors/ToArrays.java), 121 | [Primitives](https://github.com/konmik/solid/blob/master/streams/src/main/java/solid/stream/Primitives.java) 122 | 123 | # Solid collections 124 | 125 | If you're a big fan of immutable data structures like me then you also probably miss `Parcelable` interface 126 | implementation in *Guava*'s immutable collections. 127 | 128 | If you're not a big fan of immutability then you should be. 129 | 130 | I recommend reading this library description to get started with immutability: [AutoValue](https://github.com/google/auto/tree/master/value). 131 | The library has a very good Android port with `Parcelable` implementation: [AutoParcel](https://github.com/frankiesardo/auto-parcel). 132 | 133 | There is yet another library that makes a good combo with `SolidList` - [Icepick](https://github.com/frankiesardo/icepick). 134 | *Solid* collections can be safely passed between activities, services, intents 135 | and threads, and they can be automatically saved into an activity/fragment `Bundle` with just one annotation. Amazing. 136 | 137 | ### Details 138 | 139 | *Solid* collections are just a decorators around `ArrayList`, `LinkedHashMap` and `LinkedHashSet`, 140 | so I do not think that any docs are needed. 141 | `UnsupportedOperationException` will be thrown on each method that tries to modify a *solid* collection. 142 | 143 | If you're familiar with Guava's immutable collections - there is a difference that is good to know. *Solid* collections do 144 | not have a support for *Builder* pattern - use `ArrayList`, `Stream`, `Map` and `Set` to prepare them. 145 | 146 | Note that `SolidMap` is not `java.util.Collection` due to Android Parcelable Map issue (`Map` can not implement `Parcelable`). 147 | 148 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:1.3.0' 7 | } 8 | } 9 | 10 | allprojects { 11 | repositories { 12 | jcenter() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /collections/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /collections/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 10 9 | targetSdkVersion 22 10 | versionCode 2 11 | versionName "1.0.1" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | } 15 | 16 | configurations { 17 | compileJavadoc 18 | } 19 | 20 | repositories { 21 | mavenLocal() 22 | } 23 | 24 | dependencies { 25 | compile "info.android15.solid:streams:$VERSION_NAME" 26 | 27 | androidTestCompile 'junit:junit:4.12' 28 | androidTestCompile 'com.android.support.test:runner:0.3' 29 | androidTestCompile 'com.android.support.test:rules:0.3' 30 | 31 | testCompile 'junit:junit:4.12' 32 | testCompile 'org.mockito:mockito-core:2.0.12-beta' 33 | } 34 | 35 | android.libraryVariants.all { variant -> 36 | def name = variant.buildType.name 37 | if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) { 38 | return; // Skip debug builds. 39 | } 40 | def task = project.tasks.create "jar${name.capitalize()}", Jar 41 | task.dependsOn variant.javaCompile 42 | task.from variant.javaCompile.destinationDir 43 | artifacts.add('archives', task); 44 | } 45 | 46 | apply from: '../gradle/gradle-mvn-push.gradle' 47 | -------------------------------------------------------------------------------- /collections/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Solid 2 | POM_ARTIFACT_ID=collections 3 | POM_PACKAGING=jar 4 | -------------------------------------------------------------------------------- /collections/src/androidTest/java/solid/collections/SolidListTest.java: -------------------------------------------------------------------------------- 1 | package solid.collections; 2 | 3 | import android.support.test.runner.AndroidJUnit4; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.Iterator; 12 | import java.util.List; 13 | import java.util.ListIterator; 14 | 15 | import solid.functions.Func1; 16 | import testkit.ParcelFn; 17 | 18 | import static org.junit.Assert.assertArrayEquals; 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertFalse; 21 | import static org.junit.Assert.assertNotEquals; 22 | import static org.junit.Assert.assertTrue; 23 | import static solid.collections.SolidList.list; 24 | import static solid.stream.Stream.of; 25 | 26 | @RunWith(AndroidJUnit4.class) 27 | public class SolidListTest { 28 | 29 | @Test 30 | public void testParcelable() throws Exception { 31 | SolidList list = of(1, 2, 3).collect(new Func1, SolidList>() { 32 | @Override 33 | public SolidList call(Iterable iterable) { 34 | return new SolidList<>(iterable); 35 | } 36 | }); 37 | assertEquals(list, ParcelFn.unmarshall(ParcelFn.marshall(list))); 38 | } 39 | 40 | @Test 41 | public void testConstructors() throws Exception { 42 | assert123(new SolidList<>(new Integer[]{1, 2, 3})); 43 | assert123(new SolidList<>((Iterable) Arrays.asList(1, 2, 3))); 44 | assert123(new SolidList<>(Arrays.asList(1, 2, 3))); 45 | 46 | SolidList list = SolidList.empty(); 47 | assertEquals(0, list.size()); 48 | assertTrue(list.isEmpty()); 49 | } 50 | 51 | @Test 52 | public void testList() throws Exception { 53 | assert123(list(1, 2, 3)); 54 | assertEquals(0, list().size()); 55 | } 56 | 57 | @Test 58 | public void testContains() throws Exception { 59 | SolidList list1 = new SolidList<>(new Integer[]{1, 2, 3}); 60 | assertTrue(list1.contains(1)); 61 | assertTrue(list1.contains(2)); 62 | assertTrue(list1.contains(3)); 63 | assertFalse(list1.contains(4)); 64 | } 65 | 66 | @Test 67 | public void testContainsAll() throws Exception { 68 | SolidList list1 = new SolidList<>(new Integer[]{1, 2, 3}); 69 | SolidList list2 = new SolidList<>(new Integer[]{1, 2, 3}); 70 | assertTrue(list1.containsAll(list2)); 71 | } 72 | 73 | @Test 74 | public void testGet() throws Exception { 75 | SolidList list1 = new SolidList<>(new Integer[]{1, 2, 3}); 76 | assertEquals(2, (int) list1.get(1)); 77 | } 78 | 79 | @Test 80 | public void testIndexOf() throws Exception { 81 | SolidList list1 = new SolidList<>(new Integer[]{1, 2, 3}); 82 | assertEquals(0, list1.indexOf(1)); 83 | assertEquals(1, list1.indexOf(2)); 84 | assertEquals(2, list1.indexOf(3)); 85 | } 86 | 87 | @Test 88 | public void testIsEmpty() throws Exception { 89 | SolidList list1 = new SolidList<>(new Integer[]{1, 2, 3}); 90 | assertFalse(list1.isEmpty()); 91 | assertTrue(SolidList.empty().isEmpty()); 92 | } 93 | 94 | @Test 95 | public void testLastIndexOf() throws Exception { 96 | SolidList list1 = new SolidList<>(new Integer[]{1, 2, 3, 1, 2, 3}); 97 | assertEquals(3, list1.lastIndexOf(1)); 98 | assertEquals(4, list1.lastIndexOf(2)); 99 | assertEquals(5, list1.lastIndexOf(3)); 100 | } 101 | 102 | @Test 103 | public void testSize() throws Exception { 104 | SolidList list1 = new SolidList<>(new Integer[]{1, 2, 3, 1, 2, 3}); 105 | assertEquals(6, list1.size()); 106 | assertEquals(0, SolidList.empty().size()); 107 | } 108 | 109 | @Test 110 | public void testSubList() throws Exception { 111 | SolidList list1 = new SolidList<>(new Integer[]{0, 1, 2, 3, 1, 2, 3, 0}); 112 | assert123(list1.subList(1, 4)); 113 | assert123(list1.subList(4, 7)); 114 | assertEquals(0, (int) list1.subList(0, 1).get(0)); 115 | assertEquals(0, (int) list1.subList(7, 8).get(0)); 116 | assertEquals(0, list1.subList(3, 3).size()); 117 | } 118 | 119 | @Test 120 | public void testToArray() throws Exception { 121 | assertArrayEquals(new SolidList<>(new Integer[]{1, 2, 3}).toArray(), new Object[]{1, 2, 3}); 122 | } 123 | 124 | @Test 125 | public void testToArrayTyped() throws Exception { 126 | assertArrayEquals(new SolidList<>(new Integer[]{1, 2, 3}).toArray(new Integer[3]), new Integer[]{1, 2, 3}); 127 | //noinspection ToArrayCallWithZeroLengthArrayArgument 128 | assertArrayEquals(new SolidList<>(new Integer[]{1, 2, 3}).toArray(new Integer[0]), new Integer[]{1, 2, 3}); 129 | } 130 | 131 | @Test 132 | public void testEqualsHash() throws Exception { 133 | SolidList list1 = new SolidList<>(new Integer[]{0, 1, 2, 3, 1, 2, 3, 0}); 134 | SolidList list2 = new SolidList<>(new Integer[]{0, 1, 2, 3, 1, 2, 3, 0}); 135 | assertTrue(list1.equals(list2)); 136 | assertEquals(list1.hashCode(), list2.hashCode()); 137 | 138 | SolidList list3 = new SolidList<>(new Integer[]{0, 1, 2, 3, 1, 2, 3, 999}); 139 | assertFalse(list1.equals(list3)); 140 | assertNotEquals(list1.hashCode(), list3.hashCode()); 141 | 142 | List arrayList = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 1, 2, 3, 0)); 143 | assertTrue(list1.equals(arrayList)); 144 | assertTrue(arrayList.equals(list1)); 145 | assertEquals(list1.hashCode(), arrayList.hashCode()); 146 | 147 | //noinspection EqualsWithItself 148 | assertTrue(SolidList.empty().equals(SolidList.empty())); 149 | } 150 | 151 | @Test 152 | public void testToString() throws Exception { 153 | assertEquals("SolidList{list=[1, 2, 3]}", new SolidList<>(new Integer[]{1, 2, 3}).toString()); 154 | } 155 | 156 | @Test 157 | public void testIterator() throws Exception { 158 | ArrayList target = new ArrayList<>(); 159 | for (int i : new SolidList<>(new Integer[]{1, 2, 3})) 160 | target.add(i); 161 | assert123(target); 162 | } 163 | 164 | @Test 165 | public void testListIteratorPrevious() throws Exception { 166 | ListIterator iterator = new SolidList<>(new Integer[]{1, 2, 3}).listIterator(); 167 | assertFalse(iterator.hasPrevious()); 168 | 169 | iterator.next(); 170 | assertTrue(iterator.hasPrevious()); 171 | assertEquals(1, iterator.nextIndex()); 172 | 173 | iterator.next(); 174 | assertEquals(1, iterator.previousIndex()); 175 | 176 | iterator.previous(); 177 | assertEquals(0, iterator.previousIndex()); 178 | } 179 | 180 | @Test(expected = UnsupportedOperationException.class) 181 | public void testClearThrows() throws Exception { 182 | new SolidList<>(new ArrayList()).clear(); 183 | } 184 | 185 | @Test(expected = UnsupportedOperationException.class) 186 | public void testAddThrows() throws Exception { 187 | new SolidList<>(new ArrayList()).add(0); 188 | } 189 | 190 | @Test(expected = UnsupportedOperationException.class) 191 | public void testAdd2Throws() throws Exception { 192 | new SolidList<>(new ArrayList()).add(0, 0); 193 | } 194 | 195 | @Test(expected = UnsupportedOperationException.class) 196 | public void testAddAllThrows() throws Exception { 197 | new SolidList<>(new ArrayList()).addAll(new ArrayList()); 198 | } 199 | 200 | @Test(expected = UnsupportedOperationException.class) 201 | public void testAddAll2Throws() throws Exception { 202 | new SolidList<>(new ArrayList()).addAll(0, new ArrayList()); 203 | } 204 | 205 | @Test(expected = UnsupportedOperationException.class) 206 | public void testRemoveThrows() throws Exception { 207 | new SolidList<>(Collections.singletonList(0)).remove(0); 208 | } 209 | 210 | @Test(expected = UnsupportedOperationException.class) 211 | public void testRemoveObjectThrows() throws Exception { 212 | new SolidList<>(Collections.singletonList(0)).remove((Integer) 0); 213 | } 214 | 215 | @Test(expected = UnsupportedOperationException.class) 216 | public void testRemoveAllThrows() throws Exception { 217 | new SolidList<>(Collections.singletonList(0)).removeAll(Collections.singletonList(0)); 218 | } 219 | 220 | @Test(expected = UnsupportedOperationException.class) 221 | public void testRetainAllThrows() throws Exception { 222 | new SolidList<>(Collections.singletonList(0)).retainAll(Collections.singletonList(0)); 223 | } 224 | 225 | @Test(expected = UnsupportedOperationException.class) 226 | public void testSetThrows() throws Exception { 227 | new SolidList<>(Collections.singletonList(0)).set(0, 0); 228 | } 229 | 230 | @Test(expected = UnsupportedOperationException.class) 231 | public void testIteratorRemoveThrows() throws Exception { 232 | Iterator iterator = new SolidList<>(Collections.singletonList(0)).iterator(); 233 | iterator.next(); 234 | iterator.remove(); 235 | } 236 | 237 | @Test(expected = UnsupportedOperationException.class) 238 | public void testListIteratorRemoveThrows() throws Exception { 239 | ListIterator iterator = new SolidList<>(Collections.singletonList(0)).listIterator(); 240 | iterator.next(); 241 | iterator.remove(); 242 | } 243 | 244 | @Test(expected = UnsupportedOperationException.class) 245 | public void testListIteratorSetThrows() throws Exception { 246 | ListIterator iterator = new SolidList<>(Collections.singletonList(0)).listIterator(); 247 | iterator.next(); 248 | iterator.set(0); 249 | } 250 | 251 | @Test(expected = UnsupportedOperationException.class) 252 | public void testListIteratorAddThrows() throws Exception { 253 | ListIterator iterator = new SolidList<>(Collections.singletonList(0)).listIterator(); 254 | iterator.next(); 255 | iterator.add(0); 256 | } 257 | 258 | @Test 259 | public void testListIterator() throws Exception { 260 | SolidList list1 = new SolidList<>(new Integer[]{0, 1}); 261 | ListIterator iterator = list1.listIterator(1); 262 | assertTrue(iterator.hasNext()); 263 | iterator.next(); 264 | assertFalse(iterator.hasNext()); 265 | } 266 | 267 | private void assert123(List list) throws Exception { 268 | assertEquals(3, list.size()); 269 | assertEquals(1, (int) list.get(0)); 270 | assertEquals(2, (int) list.get(1)); 271 | assertEquals(3, (int) list.get(2)); 272 | } 273 | } -------------------------------------------------------------------------------- /collections/src/androidTest/java/solid/collections/SolidMapTest.java: -------------------------------------------------------------------------------- 1 | package solid.collections; 2 | 3 | import android.support.test.runner.AndroidJUnit4; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | 8 | import java.util.HashMap; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | import testkit.ParcelFn; 14 | 15 | import static org.junit.Assert.assertArrayEquals; 16 | import static org.junit.Assert.assertEquals; 17 | import static org.junit.Assert.assertFalse; 18 | import static org.junit.Assert.assertNotEquals; 19 | import static org.junit.Assert.assertTrue; 20 | import static solid.collections.SolidMap.map; 21 | 22 | @RunWith(AndroidJUnit4.class) 23 | public class SolidMapTest { 24 | @Test 25 | public void testParcelUnparcel() throws Exception { 26 | SolidMap map = new SolidMap(create123map234()); 27 | assertSetEquals(map.entrySet(), ((SolidMap) ParcelFn.unmarshall(ParcelFn.marshall(map))).entrySet()); 28 | } 29 | 30 | @Test 31 | public void testMapConstructor() throws Exception { 32 | HashMap hashMap = create123map234(); 33 | 34 | SolidMap map = new SolidMap<>(hashMap); 35 | assertEquals((Integer) 2, map.get(1)); 36 | assertEquals((Integer) 3, map.get(2)); 37 | assertEquals((Integer) 4, map.get(3)); 38 | assertEquals(3, map.size()); 39 | 40 | hashMap.put(4, 5); 41 | assertNotEquals(hashMap, map); 42 | } 43 | 44 | @Test(expected = UnsupportedOperationException.class) 45 | public void testAsMapIsImmutable() throws Exception { 46 | new SolidMap<>(create123map234()).asMap().put(1, 1); 47 | } 48 | 49 | @Test 50 | public void testEmpty() throws Exception { 51 | assertEquals(0, SolidMap.empty().size()); 52 | } 53 | 54 | @Test 55 | public void testMap() throws Exception { 56 | assertEquals(map(1, 2, 2, 3, 3, 4), new SolidMap<>(create123map234())); 57 | assertEquals(map("1", 2), new SolidMap<>(new LinkedHashMap() {{put("1", 2);}})); 58 | } 59 | 60 | @Test(expected = IllegalArgumentException.class) 61 | public void testMapOdd() throws Exception { 62 | map(1, 2, 3); 63 | } 64 | 65 | @Test 66 | public void testContainsKey() throws Exception { 67 | SolidMap map = new SolidMap<>(create123map234()); 68 | assertTrue(map.containsKey(1)); 69 | assertFalse(map.containsKey(4)); 70 | } 71 | 72 | @Test 73 | public void testContainsValue() throws Exception { 74 | SolidMap map = new SolidMap<>(create123map234()); 75 | assertTrue(map.containsValue(2)); 76 | assertFalse(map.containsValue(5)); 77 | } 78 | 79 | @Test 80 | public void testEntrySet() throws Exception { 81 | SolidMap map = new SolidMap<>(create123map234()); 82 | assertSetEquals(create123map234().entrySet(), map.entrySet()); 83 | } 84 | 85 | @Test(expected = UnsupportedOperationException.class) 86 | public void testEntrySetIsUnmodifiable() throws Exception { 87 | new SolidMap<>(create123map234()).entrySet().clear(); 88 | } 89 | 90 | @Test(expected = UnsupportedOperationException.class) 91 | public void testEntryIsUnmodifiable() throws Exception { 92 | for (Map.Entry entry : new SolidMap<>(create123map234()).entrySet()) 93 | entry.setValue(1); 94 | } 95 | 96 | @Test 97 | public void testGet() throws Exception { 98 | assertEquals((Integer) 2, new SolidMap<>(create123map234()).get(1)); 99 | assertEquals(null, new SolidMap<>(create123map234()).get(5)); 100 | } 101 | 102 | @Test 103 | public void testIsEmpty() throws Exception { 104 | assertTrue(new SolidMap<>(new HashMap<>()).isEmpty()); 105 | assertFalse(new SolidMap<>(create123map234()).isEmpty()); 106 | } 107 | 108 | @Test 109 | public void testKeySet() throws Exception { 110 | SolidMap map = new SolidMap<>(create123map234()); 111 | assertSetEquals(create123map234().keySet(), map.keySet()); 112 | } 113 | 114 | @Test(expected = UnsupportedOperationException.class) 115 | public void testKeySetIsUnmodifiable() throws Exception { 116 | new SolidMap<>(create123map234()).keySet().clear(); 117 | } 118 | 119 | @Test 120 | public void testSize() throws Exception { 121 | assertEquals(3, new SolidMap<>(create123map234()).size()); 122 | assertEquals(0, new SolidMap<>(new HashMap<>()).size()); 123 | } 124 | 125 | @Test 126 | public void testValues() throws Exception { 127 | assertArrayEquals(new Integer[]{2, 3, 4}, new SolidMap<>(create123map234()).values().toArray()); 128 | } 129 | 130 | @Test(expected = UnsupportedOperationException.class) 131 | public void testValuesIsUnmodifiable() throws Exception { 132 | new SolidMap<>(create123map234()).values().remove(1); 133 | } 134 | 135 | @Test 136 | public void testEquals() throws Exception { 137 | SolidMap map = new SolidMap<>(create123map234()); 138 | assertTrue(map.equals(map)); 139 | 140 | assertTrue(new SolidMap<>(create123map234()).equals(new SolidMap<>(create123map234()))); 141 | 142 | HashMap map234null = create123map234(); 143 | map234null.remove(1); 144 | assertFalse(map.equals(new SolidMap<>(map234null))); 145 | 146 | map234null.put(null, null); 147 | assertTrue(new SolidMap<>(map234null).equals(new SolidMap<>(map234null))); 148 | assertFalse(new SolidMap<>(create123map234()).equals(new SolidMap<>(map234null))); 149 | assertTrue(new SolidMap<>(map234null).equals(map234null)); 150 | 151 | HashMap map234null_ = create123map234(); 152 | map234null_.put(3, null); 153 | assertFalse(new SolidMap<>(map234null).equals(create123map234())); 154 | 155 | assertFalse(map.equals(1)); 156 | } 157 | 158 | @Test 159 | public void testHashCode() throws Exception { 160 | assertEquals(SolidMap.empty().hashCode(), SolidMap.empty().hashCode()); 161 | assertEquals(new SolidMap<>(create123map234()).hashCode(), new SolidMap<>(create123map234()).hashCode()); 162 | assertNotEquals(SolidMap.empty().hashCode(), new SolidMap<>(create123map234()).hashCode()); 163 | } 164 | 165 | @Test 166 | public void testIterator() throws Exception { 167 | SolidMap map = new SolidMap<>(create123map234()); 168 | HashMap hashMap = new HashMap<>(); 169 | for (Map.Entry entry : map) { 170 | hashMap.put(entry.getKey(), entry.getValue()); 171 | } 172 | assertEquals(map, new SolidMap<>(hashMap)); 173 | } 174 | 175 | @Test 176 | public void testToString() throws Exception { 177 | SolidMap map = new SolidMap<>(create123map234()); 178 | assertTrue(map.toString().contains("1")); 179 | assertTrue(map.toString().contains("4")); 180 | assertFalse(map.toString().contains("5")); 181 | } 182 | 183 | private void assertSetEquals(Set expected, Set actual) { 184 | assertEquals(expected, actual); 185 | } 186 | 187 | private LinkedHashMap create123map234() { 188 | return new LinkedHashMap() {{ 189 | put(1, 2); 190 | put(2, 3); 191 | put(3, 4); 192 | }}; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /collections/src/androidTest/java/solid/collections/SolidSetTest.java: -------------------------------------------------------------------------------- 1 | package solid.collections; 2 | 3 | import android.support.test.runner.AndroidJUnit4; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.Iterator; 12 | import java.util.Set; 13 | import java.util.TreeSet; 14 | 15 | import testkit.ParcelFn; 16 | 17 | import static org.junit.Assert.assertArrayEquals; 18 | import static org.junit.Assert.assertEquals; 19 | import static org.junit.Assert.assertFalse; 20 | import static org.junit.Assert.assertNotEquals; 21 | import static org.junit.Assert.assertTrue; 22 | import static solid.collections.SolidSet.set; 23 | 24 | @RunWith(AndroidJUnit4.class) 25 | public class SolidSetTest { 26 | 27 | @Test 28 | public void testParcelable() throws Exception { 29 | SolidSet set = new SolidSet<>(Arrays.asList(1, 2, 3)); 30 | assertEquals(set, ParcelFn.unmarshall(ParcelFn.marshall(set))); 31 | } 32 | 33 | @Test 34 | public void testConstructors() throws Exception { 35 | assert123(new SolidSet<>(new Integer[]{1, 2, 3})); 36 | assert123(new SolidSet<>(Arrays.asList(1, 2, 3))); 37 | assert123(new SolidSet<>(Arrays.asList(1, 2, 3, 3, 2, 1))); 38 | assert123(new SolidSet<>((Iterable) Arrays.asList(1, 2, 3))); 39 | assert123(new SolidSet<>((Iterable) Arrays.asList(1, 2, 3), 3)); 40 | 41 | assertTrue(new SolidSet<>(Collections.singletonList(1)).contains(1)); 42 | assertEquals(1, new SolidSet<>(Collections.singletonList(1)).size()); 43 | assertEquals(0, new SolidSet<>(Collections.emptyList()).size()); 44 | assertTrue(new SolidSet<>(Collections.singletonList(null)).contains(null)); 45 | } 46 | 47 | @Test 48 | public void testSet() throws Exception { 49 | assert123(set(1, 2, 3)); 50 | assertEquals(0, set().size()); 51 | } 52 | 53 | @Test 54 | public void testContains() throws Exception { 55 | assertTrue(new SolidSet<>(Arrays.asList(1, 2, 3)).contains(1)); 56 | assertFalse(new SolidSet<>(Arrays.asList(1, 2, 3)).contains(0)); 57 | assertTrue(new SolidSet<>(Arrays.asList(1, null, 3)).contains(null)); 58 | } 59 | 60 | @Test 61 | public void testContainsAll() throws Exception { 62 | assertTrue(new SolidSet<>(Arrays.asList(1, 2, 3)).containsAll(Arrays.asList(3, 2, 1))); 63 | assertTrue(new SolidSet<>(Arrays.asList(1, null, 3)).containsAll(Arrays.asList(null, 1, 3))); 64 | } 65 | 66 | @Test 67 | public void testIsEmpty() throws Exception { 68 | assertFalse(new SolidSet<>(Arrays.asList(1, 2, 3)).isEmpty()); 69 | assertTrue(new SolidSet<>(Collections.emptyList()).isEmpty()); 70 | } 71 | 72 | @Test 73 | public void testSize() throws Exception { 74 | assertEquals(3, new SolidSet<>(Arrays.asList(1, 2, 3)).size()); 75 | assertEquals(0, new SolidSet<>(Collections.emptyList()).size()); 76 | } 77 | 78 | @Test 79 | public void testToArray() throws Exception { 80 | assertArrayEquals(new SolidSet<>(new Integer[]{1, 2, 3}).toArray(), new Object[]{1, 2, 3}); 81 | } 82 | 83 | @Test 84 | public void testToArrayTyped() throws Exception { 85 | assertArrayEquals(new SolidSet<>(new Integer[]{1, 2, 3}).toArray(new Integer[3]), new Integer[]{1, 2, 3}); 86 | //noinspection ToArrayCallWithZeroLengthArrayArgument 87 | assertArrayEquals(new SolidSet<>(new Integer[]{1, 2, 3}).toArray(new Integer[0]), new Integer[]{1, 2, 3}); 88 | } 89 | 90 | @Test 91 | public void testIterator() throws Exception { 92 | ArrayList target = new ArrayList<>(); 93 | for (int i : new SolidSet<>(new Integer[]{1, 2, 3})) 94 | target.add(i); 95 | assert123(new SolidSet<>(target)); 96 | } 97 | 98 | @Test(expected = UnsupportedOperationException.class) 99 | public void testIteratorImmutable() throws Exception { 100 | Iterator iterator = new SolidSet<>(new Integer[]{1, 2, 3}).iterator(); 101 | iterator.next(); 102 | iterator.remove(); 103 | } 104 | 105 | @Test(expected = UnsupportedOperationException.class) 106 | public void testAdd() throws Exception { 107 | new SolidSet<>(new Integer[]{1, 2, 3}).add(1); 108 | } 109 | 110 | @Test(expected = UnsupportedOperationException.class) 111 | public void testAddAll() throws Exception { 112 | new SolidSet<>(new Integer[]{1, 2, 3}).addAll(Arrays.asList(1, 2, 3)); 113 | } 114 | 115 | @Test(expected = UnsupportedOperationException.class) 116 | public void testClear() throws Exception { 117 | new SolidSet<>(new Integer[]{1, 2, 3}).clear(); 118 | } 119 | 120 | @Test(expected = UnsupportedOperationException.class) 121 | public void testRemove() throws Exception { 122 | new SolidSet<>(new Integer[]{1, 2, 3}).remove(1); 123 | } 124 | 125 | @Test(expected = UnsupportedOperationException.class) 126 | public void testRemoveAll() throws Exception { 127 | new SolidSet<>(new Integer[]{1, 2, 3}).removeAll(Arrays.asList(1, 2, 3)); 128 | } 129 | 130 | @Test(expected = UnsupportedOperationException.class) 131 | public void testRetainAll() throws Exception { 132 | new SolidSet<>(new Integer[]{1, 2, 3}).retainAll(Arrays.asList(2, 3)); 133 | } 134 | 135 | @Test 136 | public void testEmpty() throws Exception { 137 | assertEquals(0, SolidSet.empty().size()); 138 | } 139 | 140 | @Test 141 | public void testToString() throws Exception { 142 | assertTrue(new SolidSet<>(new Integer[]{1, 13, 3}).toString().contains("13")); 143 | } 144 | 145 | @Test 146 | public void testHashCode() throws Exception { 147 | assertEquals(new SolidSet<>(new Integer[]{1, 13, 3}).hashCode(), new SolidSet<>(new Integer[]{1, 13, 3}).hashCode()); 148 | assertNotEquals(SolidSet.empty().hashCode(), new SolidSet<>(new Integer[]{1, 13, 3}).hashCode()); 149 | 150 | Set treeSet = new TreeSet<>(SolidSet.set(1, 13, 3)); 151 | assertEquals(new SolidSet<>(new Integer[]{1, 13, 3}).hashCode(), treeSet.hashCode()); 152 | } 153 | 154 | @Test 155 | public void testEquals() throws Exception { 156 | assertEquals(new SolidSet<>(new Integer[]{1, 13, 3}), new SolidSet<>(new Integer[]{1, 13, 3})); 157 | assertNotEquals(SolidSet.empty(), new SolidSet<>(new Integer[]{1, 13, 3})); 158 | 159 | Set treeSet = new TreeSet<>(SolidSet.set(1, 13, 3)); 160 | assertEquals(new SolidSet<>(new Integer[]{1, 13, 3}), treeSet); 161 | assertEquals(treeSet, new SolidSet<>(new Integer[]{1, 13, 3})); 162 | } 163 | 164 | private void assert123(Set set) throws Exception { 165 | assertEquals(3, set.size()); 166 | assertTrue(set.contains(1)); 167 | assertTrue(set.contains(2)); 168 | assertTrue(set.contains(3)); 169 | } 170 | } -------------------------------------------------------------------------------- /collections/src/androidTest/java/solid/collectors/ToSolidListTest.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Collections; 6 | 7 | import solid.stream.Stream; 8 | 9 | import static java.util.Arrays.asList; 10 | import static solid.stream.Stream.of; 11 | import static testkit.AssertIterableEquals.assertIterableEquals; 12 | 13 | public class ToSolidListTest { 14 | @Test 15 | public void testToSolidList() throws Exception { 16 | assertIterableEquals(asList(1, 2, 3), of(1, 2, 3).collect(ToSolidList.toSolidList())); 17 | assertIterableEquals(Collections.emptyList(), Stream.of().collect(ToSolidList.toSolidList())); 18 | } 19 | } -------------------------------------------------------------------------------- /collections/src/androidTest/java/solid/collectors/ToSolidMapTest.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import android.support.test.runner.AndroidJUnit4; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | 8 | import java.util.LinkedHashMap; 9 | 10 | import solid.collections.Pair; 11 | import solid.collections.SolidMap; 12 | import solid.functions.Func1; 13 | import solid.stream.Range; 14 | 15 | import static java.lang.String.valueOf; 16 | import static testkit.AssertIterableEquals.assertIterableEquals; 17 | 18 | @RunWith(AndroidJUnit4.class) 19 | public class ToSolidMapTest { 20 | 21 | public static final SolidMap MAP = new SolidMap<>(new LinkedHashMap() {{ 22 | put("1", 1); 23 | put("2", 2); 24 | put("3", 3); 25 | }}); 26 | 27 | @Test 28 | public void testToSolidMap2() throws Exception { 29 | assertIterableEquals(MAP, Range.range(1, 4).collect(ToSolidMap.toSolidMap(new Func1() { 30 | @Override 31 | public String call(Integer it) {return valueOf(it);} 32 | }, new Func1() { 33 | @Override 34 | public Integer call(Integer value) { 35 | return value; 36 | } 37 | }))); 38 | } 39 | 40 | @Test 41 | public void testToSolidMap1() throws Exception { 42 | assertIterableEquals(MAP, Range.range(1, 4).collect(ToSolidMap.toSolidMap(new Func1() { 43 | @Override 44 | public String call(Integer it) {return valueOf(it);} 45 | }))); 46 | } 47 | 48 | @Test 49 | public void testToSolidMapType() throws Exception { 50 | SolidMap converted = Range.range(1, 4) 51 | .map(new Func1>() { 52 | @Override 53 | public Pair call(Integer it) {return new Pair<>(valueOf(it), it);} 54 | }) 55 | .collect(ToSolidMap.pairsToSolidMap()); 56 | assertIterableEquals(MAP, converted); 57 | } 58 | 59 | @Test 60 | public void testToSolidMapFromPairs() throws Exception { 61 | SolidMap converted = Range.range(1, 4) 62 | .map(new Func1>() { 63 | @Override 64 | public Pair call(Integer it) {return new Pair<>(valueOf(it), it);} 65 | }) 66 | .collect(ToSolidMap.pairsToSolidMap()); 67 | 68 | assertIterableEquals(MAP, converted); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /collections/src/androidTest/java/solid/collectors/ToSolidSetTest.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Collections; 6 | 7 | import solid.stream.Stream; 8 | 9 | import static java.util.Arrays.asList; 10 | import static solid.stream.Stream.of; 11 | import static testkit.AssertIterableEquals.assertIterableEquals; 12 | 13 | public class ToSolidSetTest { 14 | @Test 15 | public void testToSolidSet() throws Exception { 16 | assertIterableEquals(asList(1, 2, 3), of(1, 2, 3).collect(ToSolidSet.toSolidSet())); 17 | assertIterableEquals(Collections.emptyList(), Stream.of().collect(ToSolidSet.toSolidSet())); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /collections/src/androidTest/java/solid/collectors/ToSparseArrayTest.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import android.support.test.runner.AndroidJUnit4; 4 | import android.util.SparseArray; 5 | 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import java.util.ArrayList; 11 | 12 | import solid.functions.Func1; 13 | 14 | import static java.util.Arrays.asList; 15 | import static org.junit.Assert.assertEquals; 16 | import static solid.collectors.ToSparseArray.toSparseArray; 17 | import static solid.stream.Stream.stream; 18 | 19 | @RunWith(AndroidJUnit4.class) 20 | public class ToSparseArrayTest { 21 | @Test 22 | public void testToSparseArray() throws Exception { 23 | assert123(stream(asList("1", "2", "3")) 24 | .collect(ToSparseArray.toSparseArray(new Func1() { 25 | @Override 26 | public Integer call(String value) { 27 | return Integer.parseInt(value); 28 | } 29 | }))); 30 | 31 | assert123(stream(asList("1", "2", "3")) 32 | .collect(ToSparseArray.toSparseArray(new Func1() { 33 | @Override 34 | public Integer call(String value) { 35 | return Integer.parseInt(value); 36 | } 37 | }, 10))); 38 | 39 | Assert.assertEquals(0, stream(new ArrayList<>()).collect(ToSparseArray.toSparseArray(null)).size()); 40 | } 41 | 42 | private void assert123(SparseArray array4) { 43 | assertEquals(3, array4.size()); 44 | assertEquals("1", array4.get(1)); 45 | assertEquals("2", array4.get(2)); 46 | assertEquals("3", array4.get(3)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /collections/src/androidTest/java/testkit/AssertIterableEquals.java: -------------------------------------------------------------------------------- 1 | package testkit; 2 | 3 | import java.util.Iterator; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.assertFalse; 7 | 8 | public class AssertIterableEquals { 9 | public static void assertIterableEquals(Iterable iterable1, Iterable iterable2) { 10 | Iterator iterator1 = iterable1.iterator(); 11 | Iterator iterator2 = iterable2.iterator(); 12 | while (iterator1.hasNext() && iterator2.hasNext()) 13 | assertEquals(iterator1.next(), iterator2.next()); 14 | assertFalse(iterator1.hasNext()); 15 | assertFalse(iterator2.hasNext()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /collections/src/androidTest/java/testkit/ParcelFn.java: -------------------------------------------------------------------------------- 1 | package testkit; 2 | 3 | import android.os.Parcel; 4 | 5 | public class ParcelFn { 6 | 7 | private static final ClassLoader CLASS_LOADER = ParcelFn.class.getClassLoader(); 8 | 9 | public static T unmarshall(byte[] array) { 10 | Parcel parcel = Parcel.obtain(); 11 | parcel.unmarshall(array, 0, array.length); 12 | parcel.setDataPosition(0); 13 | Object value = parcel.readValue(CLASS_LOADER); 14 | parcel.recycle(); 15 | return (T) value; 16 | } 17 | 18 | public static byte[] marshall(Object o) { 19 | Parcel parcel = Parcel.obtain(); 20 | parcel.writeValue(o); 21 | byte[] result = parcel.marshall(); 22 | parcel.recycle(); 23 | return result; 24 | } 25 | } -------------------------------------------------------------------------------- /collections/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /collections/src/main/java/solid/collections/SolidList.java: -------------------------------------------------------------------------------- 1 | package solid.collections; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | import java.util.Iterator; 10 | import java.util.List; 11 | import java.util.ListIterator; 12 | 13 | import solid.stream.Stream; 14 | 15 | import static java.util.Arrays.asList; 16 | 17 | /** 18 | * Represents an immutable parcelable list. 19 | * This is basically a decorator around ArrayList. 20 | * 21 | * @param A type of data in the list. 22 | */ 23 | public class SolidList extends Stream implements List, Parcelable { 24 | 25 | private static final SolidList EMPTY = new SolidList<>(Collections.emptyList()); 26 | 27 | private final List list; 28 | 29 | /** 30 | * Creates and returns a new {@link SolidList} from an array. 31 | * 32 | * @param array a source of data for {@link SolidList}. 33 | */ 34 | public SolidList(T[] array) { 35 | this(asList(array)); 36 | } 37 | 38 | /** 39 | * Creates a new {@link SolidList} from an {@link Iterable}. 40 | * 41 | * @param iterable a source of data for the new {@link SolidList}. 42 | */ 43 | public SolidList(Iterable iterable) { 44 | this(iterable, 0); 45 | } 46 | 47 | /** 48 | * Creates a new {@link SolidList} from an {@link Iterable}. Provides the possibility 49 | * to define an initial capacity of the list for performance gain on lists that exceed 12 items. 50 | * 51 | * @param initialCapacity initial capacity of the list. 52 | * @param iterable a source of data for the new {@link SolidList}. 53 | */ 54 | public SolidList(Iterable iterable, int initialCapacity) { 55 | ArrayList list = new ArrayList<>(initialCapacity); 56 | for (T value : iterable) 57 | list.add(value); 58 | this.list = Collections.unmodifiableList(list); 59 | } 60 | 61 | /** 62 | * Creates a new {@link SolidList} from a {@link Collection}. 63 | * 64 | * @param collection a source of data for the new {@link SolidList}. 65 | */ 66 | public SolidList(Collection collection) { 67 | this(collection, collection.size()); 68 | } 69 | 70 | /** 71 | * Returns an empty {@link SolidList}. 72 | * 73 | * @param a type of list to return. 74 | * @return an empty {@link SolidList}. 75 | */ 76 | public static SolidList empty() { 77 | //noinspection unchecked 78 | return (SolidList) EMPTY; 79 | } 80 | 81 | /** 82 | * Creates a {@link SolidList} from given arguments. 83 | * 84 | * @param items items to create list from. 85 | * @param a type of list items to return. 86 | * @return a {@link SolidList} created from items. 87 | */ 88 | public static SolidList list(T... items) { 89 | return new SolidList<>(items); 90 | } 91 | 92 | @Deprecated 93 | @Override 94 | public void add(int location, T object) { 95 | throw new UnsupportedOperationException(); 96 | } 97 | 98 | @Deprecated 99 | @Override 100 | public boolean add(T object) { 101 | throw new UnsupportedOperationException(); 102 | } 103 | 104 | @Deprecated 105 | @Override 106 | public boolean addAll(int location, Collection collection) { 107 | throw new UnsupportedOperationException(); 108 | } 109 | 110 | @Deprecated 111 | @Override 112 | public boolean addAll(Collection collection) { 113 | throw new UnsupportedOperationException(); 114 | } 115 | 116 | @Deprecated 117 | @Override 118 | public void clear() { 119 | throw new UnsupportedOperationException(); 120 | } 121 | 122 | @Override 123 | public boolean contains(Object object) { 124 | return list.contains(object); 125 | } 126 | 127 | @Override 128 | public boolean containsAll(Collection collection) { 129 | return list.containsAll(collection); 130 | } 131 | 132 | @Override 133 | public T get(int location) { 134 | return list.get(location); 135 | } 136 | 137 | @Override 138 | public int indexOf(Object object) { 139 | return list.indexOf(object); 140 | } 141 | 142 | @Override 143 | public boolean isEmpty() { 144 | return list.isEmpty(); 145 | } 146 | 147 | @Override 148 | public Iterator iterator() { 149 | return list.iterator(); 150 | } 151 | 152 | @Override 153 | public int lastIndexOf(Object object) { 154 | return list.lastIndexOf(object); 155 | } 156 | 157 | @Override 158 | public ListIterator listIterator() { 159 | return list.listIterator(); 160 | } 161 | 162 | @Override 163 | public ListIterator listIterator(int location) { 164 | return list.listIterator(location); 165 | } 166 | 167 | @Deprecated 168 | @Override 169 | public T remove(int location) { 170 | throw new UnsupportedOperationException(); 171 | } 172 | 173 | @Deprecated 174 | @Override 175 | public boolean remove(Object object) { 176 | throw new UnsupportedOperationException(); 177 | } 178 | 179 | @Deprecated 180 | @Override 181 | public boolean removeAll(Collection collection) { 182 | throw new UnsupportedOperationException(); 183 | } 184 | 185 | @Deprecated 186 | @Override 187 | public boolean retainAll(Collection collection) { 188 | throw new UnsupportedOperationException(); 189 | } 190 | 191 | @Deprecated 192 | @Override 193 | public T set(int location, T object) { 194 | throw new UnsupportedOperationException(); 195 | } 196 | 197 | @Override 198 | public int size() { 199 | return list.size(); 200 | } 201 | 202 | @Override 203 | public SolidList subList(int start, int end) { 204 | return new SolidList<>(list.subList(start, end)); 205 | } 206 | 207 | @Override 208 | public Object[] toArray() { 209 | return list.toArray(); 210 | } 211 | 212 | @Override 213 | public T1[] toArray(T1[] contents) { 214 | return list.toArray(contents); 215 | } 216 | 217 | private static final ClassLoader CLASS_LOADER = SolidList.class.getClassLoader(); 218 | 219 | @Override 220 | public int describeContents() { 221 | return 0; 222 | } 223 | 224 | protected SolidList(Parcel in) { 225 | //noinspection unchecked,unchecked 226 | ArrayList temp = new ArrayList<>(); 227 | in.readList(temp, CLASS_LOADER); 228 | list = Collections.unmodifiableList(temp); 229 | } 230 | 231 | @Override 232 | public void writeToParcel(Parcel dest, int flags) { 233 | dest.writeList(list); 234 | } 235 | 236 | public static final Creator CREATOR = new Creator() { 237 | public SolidList createFromParcel(Parcel in) { 238 | return new SolidList(in); 239 | } 240 | 241 | public SolidList[] newArray(int size) { 242 | return new SolidList[size]; 243 | } 244 | }; 245 | 246 | @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") 247 | @Override 248 | public boolean equals(Object o) { 249 | if (this == o) return true; 250 | return list.equals(o); 251 | } 252 | 253 | @Override 254 | public int hashCode() { 255 | return list.hashCode(); 256 | } 257 | 258 | @Override 259 | public String toString() { 260 | return "SolidList{" + 261 | "list=" + list + 262 | '}'; 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /collections/src/main/java/solid/collections/SolidMap.java: -------------------------------------------------------------------------------- 1 | package solid.collections; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import java.util.Collection; 7 | import java.util.Collections; 8 | import java.util.Iterator; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | import solid.stream.Stream; 14 | 15 | /** 16 | * Represents an immutable parcelable map. 17 | * This is basically a decorator around {@link java.util.LinkedHashMap}. 18 | * 19 | * {@link SolidMap} does not extend {@link java.util.Map} because of 20 | * {@link java.util.Map} interferes with {@link Parcelable} when putting into 21 | * {@link Parcel}, see {@link Parcel#writeValue(Object)}. 22 | * 23 | * Use {@link SolidMap#asMap()}. 24 | * 25 | * @param a type of keys. 26 | * @param a type of values. 27 | */ 28 | public class SolidMap extends Stream> implements Parcelable { 29 | 30 | private static final SolidMap EMPTY = new SolidMap<>(Collections.emptyMap()); 31 | 32 | private final Map map; 33 | 34 | /** 35 | * Constructs a SolidMap from a given map. 36 | * 37 | * @param map a source map. 38 | */ 39 | public SolidMap(Map map) { 40 | this.map = Collections.unmodifiableMap(new LinkedHashMap<>(map)); 41 | } 42 | 43 | /** 44 | * Constructs a SolidMap from a given iterable stream of entries. 45 | * 46 | * @param iterable a source iterable. 47 | */ 48 | public SolidMap(Iterable> iterable) { 49 | LinkedHashMap m = new LinkedHashMap<>(); 50 | for (Pair pair : iterable) 51 | m.put(pair.first, pair.second); 52 | this.map = Collections.unmodifiableMap(m); 53 | } 54 | 55 | /** 56 | * Returns an empty {@link SolidMap}. 57 | * 58 | * @param a type of keys. 59 | * @param a type of values. 60 | * @return an empty {@link SolidMap}. 61 | */ 62 | public static SolidMap empty() { 63 | //noinspection unchecked 64 | return (SolidMap) EMPTY; 65 | } 66 | 67 | /** 68 | * Creates a map using interleaving keys and values. 69 | * 70 | * Warning: this method does not provide type safety. 71 | * 72 | * @param key first map key 73 | * @param value first map value 74 | * @param pairs items that will be transformed into value-map pairs. Warning: there is no 75 | * type safety here! 76 | * @param type of map keys 77 | * @param type of map values 78 | * @return a SolidMap that was constructed from given keys and values 79 | */ 80 | public static SolidMap map(K key, V value, Object... pairs) { 81 | if (pairs.length % 2 != 0) 82 | throw new IllegalArgumentException("SolidMap.map(...) takes even number of arguments"); 83 | LinkedHashMap m = new LinkedHashMap<>(); 84 | m.put(key, value); 85 | for (int i = 0; i < pairs.length; i += 2) 86 | m.put((K) pairs[i], (V) pairs[i + 1]); 87 | return new SolidMap<>(m); 88 | } 89 | 90 | /** 91 | * Returns an immutable {@link Map} interface. 92 | */ 93 | public Map asMap() { 94 | return map; 95 | } 96 | 97 | public boolean containsKey(Object key) { 98 | return map.containsKey(key); 99 | } 100 | 101 | public boolean containsValue(Object value) { 102 | return map.containsKey(value); 103 | } 104 | 105 | public Set> entrySet() { 106 | return map.entrySet(); 107 | } 108 | 109 | public V get(Object key) { 110 | return map.get(key); 111 | } 112 | 113 | public boolean isEmpty() { 114 | return map.isEmpty(); 115 | } 116 | 117 | public Set keySet() { 118 | return map.keySet(); 119 | } 120 | 121 | public int size() { 122 | return map.size(); 123 | } 124 | 125 | public Collection values() { 126 | return map.values(); 127 | } 128 | 129 | private static final ClassLoader CLASS_LOADER = SolidMap.class.getClassLoader(); 130 | 131 | @Override 132 | public int describeContents() { 133 | return 0; 134 | } 135 | 136 | public SolidMap(Parcel in) { 137 | LinkedHashMap temp = new LinkedHashMap<>(); 138 | in.readMap(temp, CLASS_LOADER); 139 | //noinspection unchecked 140 | map = Collections.unmodifiableMap(temp); 141 | } 142 | 143 | @Override 144 | public void writeToParcel(Parcel dest, int flags) { 145 | dest.writeMap(map); 146 | } 147 | 148 | public static final Creator CREATOR = new Creator() { 149 | @Override 150 | public SolidMap createFromParcel(Parcel in) { 151 | return new SolidMap(in); 152 | } 153 | 154 | @Override 155 | public SolidMap[] newArray(int size) { 156 | return new SolidMap[size]; 157 | } 158 | }; 159 | 160 | @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") 161 | @Override 162 | public boolean equals(Object o) { 163 | if (o instanceof Map) 164 | return map.equals(o); 165 | else if (o instanceof SolidMap) 166 | return map.equals(((SolidMap) o).map); 167 | else 168 | return false; 169 | } 170 | 171 | @Override 172 | public int hashCode() { 173 | return map.hashCode(); 174 | } 175 | 176 | @Override 177 | public String toString() { 178 | return "SolidMap{" + 179 | "map=" + map + 180 | '}'; 181 | } 182 | 183 | @Override 184 | public Iterator> iterator() { 185 | return map.entrySet().iterator(); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /collections/src/main/java/solid/collections/SolidSet.java: -------------------------------------------------------------------------------- 1 | package solid.collections; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import java.util.Iterator; 11 | import java.util.LinkedHashSet; 12 | import java.util.Set; 13 | 14 | import solid.stream.Stream; 15 | 16 | /** 17 | * Represents an immutable parcelable set. 18 | * This is basically a decorator around LinkedHashSet. 19 | * 20 | * @param A type of data in the list. 21 | */ 22 | public class SolidSet extends Stream implements Set, Parcelable { 23 | 24 | private static final Set EMPTY = new SolidSet<>(Collections.emptySet()); 25 | 26 | private final Set set; 27 | 28 | public SolidSet(T[] array) { 29 | this(Arrays.asList(array)); 30 | } 31 | 32 | public SolidSet(Collection collection) { 33 | this.set = Collections.unmodifiableSet(new LinkedHashSet<>(collection)); 34 | } 35 | 36 | public SolidSet(Iterable iterable) { 37 | this(iterable, 0); 38 | } 39 | 40 | public SolidSet(Iterable iterable, int initialCapacity) { 41 | Set set = new LinkedHashSet<>(initialCapacity); 42 | for (T value : iterable) 43 | set.add(value); 44 | this.set = Collections.unmodifiableSet(set); 45 | } 46 | 47 | public static SolidSet empty() { 48 | //noinspection unchecked 49 | return (SolidSet) EMPTY; 50 | } 51 | 52 | /** 53 | * Creates a SolidSet from given items. 54 | * 55 | * @param items items to create SolidSet from. 56 | * @param a type if set items. 57 | * @return a SolidSet from given items. 58 | */ 59 | public static SolidSet set(T... items) { 60 | return new SolidSet<>(items); 61 | } 62 | 63 | @Override 64 | public boolean contains(Object object) { 65 | return set.contains(object); 66 | } 67 | 68 | @Override 69 | public boolean containsAll(Collection collection) { 70 | return set.containsAll(collection); 71 | } 72 | 73 | @Override 74 | public boolean isEmpty() { 75 | return set.isEmpty(); 76 | } 77 | 78 | @Override 79 | public int size() { 80 | return set.size(); 81 | } 82 | 83 | @Override 84 | public Object[] toArray() { 85 | return set.toArray(); 86 | } 87 | 88 | @Override 89 | public T1[] toArray(T1[] array) { 90 | return set.toArray(array); 91 | } 92 | 93 | @Override 94 | public Iterator iterator() { 95 | return set.iterator(); 96 | } 97 | 98 | @Deprecated 99 | @Override 100 | public boolean add(T object) { 101 | throw new UnsupportedOperationException(); 102 | } 103 | 104 | @Deprecated 105 | @Override 106 | public boolean addAll(Collection collection) { 107 | throw new UnsupportedOperationException(); 108 | } 109 | 110 | @Deprecated 111 | @Override 112 | public void clear() { 113 | throw new UnsupportedOperationException(); 114 | } 115 | 116 | @Deprecated 117 | @Override 118 | public boolean remove(Object object) { 119 | throw new UnsupportedOperationException(); 120 | } 121 | 122 | @Deprecated 123 | @Override 124 | public boolean removeAll(Collection collection) { 125 | throw new UnsupportedOperationException(); 126 | } 127 | 128 | @Deprecated 129 | @Override 130 | public boolean retainAll(Collection collection) { 131 | throw new UnsupportedOperationException(); 132 | } 133 | 134 | private static final ClassLoader CLASS_LOADER = SolidSet.class.getClassLoader(); 135 | 136 | protected SolidSet(Parcel in) { 137 | set = Collections.unmodifiableSet(new LinkedHashSet<>(in.readArrayList(CLASS_LOADER))); 138 | } 139 | 140 | @Override 141 | public void writeToParcel(Parcel dest, int flags) { 142 | dest.writeList(new ArrayList(set)); 143 | } 144 | 145 | @Override 146 | public int describeContents() { 147 | return 0; 148 | } 149 | 150 | public static final Creator CREATOR = new Creator() { 151 | @Override 152 | public SolidSet createFromParcel(Parcel in) { 153 | return new SolidSet(in); 154 | } 155 | 156 | @Override 157 | public SolidSet[] newArray(int size) { 158 | return new SolidSet[size]; 159 | } 160 | }; 161 | 162 | @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") 163 | @Override 164 | public boolean equals(Object o) { 165 | if (this == o) return true; 166 | return set.equals(o); 167 | } 168 | 169 | @Override 170 | public int hashCode() { 171 | return set.hashCode(); 172 | } 173 | 174 | @Override 175 | public String toString() { 176 | return "SolidSet{" + 177 | "set=" + set + 178 | '}'; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /collections/src/main/java/solid/collectors/ToSolidList.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import solid.collections.SolidList; 7 | import solid.functions.Func1; 8 | 9 | public class ToSolidList { 10 | 11 | private static final Func1 TO_SOLID_LIST = toSolidList(0); 12 | 13 | /** 14 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 15 | * to convert a stream into a {@link ArrayList}. 16 | * 17 | * @param a type of {@link ArrayList} items. 18 | * @return a method that converts an iterable into {@link ArrayList}. 19 | */ 20 | public static Func1, SolidList> toSolidList() { 21 | return TO_SOLID_LIST; 22 | } 23 | 24 | /** 25 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 26 | * to convert a stream into a {@link List}. 27 | *

28 | * Use this method instead of {@link #toSolidList()} for better performance on 29 | * streams that can have more than 12 items. 30 | * 31 | * @param a type of {@link List} items. 32 | * @param initialCapacity initial capacity of the list. 33 | * @return a method that converts an iterable into {@link List}. 34 | */ 35 | public static Func1, SolidList> toSolidList(final int initialCapacity) { 36 | return new Func1, SolidList>() { 37 | @Override 38 | public SolidList call(Iterable iterable) { 39 | ArrayList list = new ArrayList<>(initialCapacity); 40 | for (T value : iterable) 41 | list.add(value); 42 | return new SolidList<>(list); 43 | } 44 | }; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /collections/src/main/java/solid/collectors/ToSolidMap.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import java.util.Map; 4 | 5 | import solid.collections.Pair; 6 | import solid.collections.SolidMap; 7 | import solid.functions.Func1; 8 | 9 | import static solid.stream.Stream.stream; 10 | 11 | public class ToSolidMap { 12 | 13 | /** 14 | * Returns a function that converts a stream into {@link SolidMap} using given key and value extractor methods. 15 | */ 16 | public static Func1, SolidMap> toSolidMap(final Func1 keyExtractor, final Func1 valueExtractor) { 17 | return new Func1, SolidMap>() { 18 | @Override 19 | public SolidMap call(final Iterable iterable) { 20 | return new SolidMap<>( 21 | stream(iterable).map(new Func1>() { 22 | @Override 23 | public Pair call(T value) { 24 | return new Pair<>(keyExtractor.call(value), valueExtractor.call(value)); 25 | } 26 | })); 27 | } 28 | }; 29 | } 30 | 31 | /** 32 | * Returns a function that converts a stream into {@link SolidMap} using a given key extractor method. 33 | */ 34 | public static Func1, SolidMap> toSolidMap(final Func1 keyExtractor) { 35 | return toSolidMap(keyExtractor, new Func1() { 36 | @Override 37 | public T call(T value) { 38 | return value; 39 | } 40 | }); 41 | } 42 | 43 | /** 44 | * Returns a function that converts a stream of {@link java.util.Map.Entry} into {@link SolidMap}. 45 | */ 46 | public static Func1>, SolidMap> toSolidMap() { 47 | return new Func1>, SolidMap>() { 48 | @Override 49 | public SolidMap call(Iterable> iterable) { 50 | return new SolidMap<>(stream(iterable).map(new Func1, Pair>() { 51 | @Override 52 | public Pair call(Map.Entry value) { 53 | return new Pair<>(value.getKey(), value.getValue()); 54 | } 55 | })); 56 | } 57 | }; 58 | } 59 | 60 | /** 61 | * Returns a function that converts a stream of {@link Pair} into {@link SolidMap}. 62 | */ 63 | public static Func1>, SolidMap> pairsToSolidMap() { 64 | return new Func1>, SolidMap>() { 65 | @Override 66 | public SolidMap call(Iterable> iterable) { 67 | return new SolidMap<>(iterable); 68 | } 69 | }; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /collections/src/main/java/solid/collectors/ToSolidSet.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import solid.collections.SolidSet; 7 | import solid.functions.Func1; 8 | 9 | public class ToSolidSet { 10 | 11 | private static final Func1 TO_SOLID_SET = toSolidSet(0); 12 | 13 | /** 14 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 15 | * to convert a stream into a {@link ArrayList}. 16 | * 17 | * @param a type of {@link ArrayList} items. 18 | * @return a method that converts an iterable into {@link ArrayList}. 19 | */ 20 | public static Func1, SolidSet> toSolidSet() { 21 | return TO_SOLID_SET; 22 | } 23 | 24 | /** 25 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 26 | * to convert a stream into a {@link List}. 27 | *

28 | * Use this method instead of {@link #toSolidSet()} for better performance on 29 | * streams that can have more than 12 items. 30 | * 31 | * @param a type of {@link List} items. 32 | * @param initialCapacity initial capacity of the list. 33 | * @return a method that converts an iterable into {@link List}. 34 | */ 35 | public static Func1, SolidSet> toSolidSet(final int initialCapacity) { 36 | return new Func1, SolidSet>() { 37 | @Override 38 | public SolidSet call(Iterable iterable) { 39 | return new SolidSet<>(iterable, initialCapacity); 40 | } 41 | }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /collections/src/main/java/solid/collectors/ToSparseArray.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import android.util.SparseArray; 4 | 5 | import solid.functions.Func1; 6 | 7 | public class ToSparseArray { 8 | 9 | /** 10 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 11 | * to convert a stream into a {@link SparseArray}. 12 | * 13 | * @param a type of stream items. 14 | * @param itemToKey a method that should return a key for an item. 15 | * @return a method that converts an iterable into a {@link SparseArray}. 16 | */ 17 | public static Func1, SparseArray> toSparseArray(Func1 itemToKey) { 18 | return toSparseArray(itemToKey, 10); 19 | } 20 | 21 | /** 22 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 23 | * to convert a stream into a {@link SparseArray}. 24 | *

25 | * Use this method instead of {@link #toSparseArray(Func1)}} for better performance on 26 | * streams that can have more than 10 items. 27 | * 28 | * @param a type of stream items. 29 | * @param itemToKey a method that should return a key for an item. 30 | * @param initialCapacity initial capacity on the sparse array. 31 | * @return a method that converts an iterable into a {@link SparseArray}. 32 | */ 33 | public static Func1, SparseArray> toSparseArray(final Func1 itemToKey, final int initialCapacity) { 34 | return new Func1, SparseArray>() { 35 | @Override 36 | public SparseArray call(Iterable iterable) { 37 | SparseArray array = new SparseArray<>(initialCapacity); 38 | for (T value : iterable) 39 | array.put(itemToKey.call(value), value); 40 | return array; 41 | } 42 | }; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | VERSION_CODE=3010 2 | VERSION_NAME=3.0.1 3 | GROUP=info.android15.solid 4 | 5 | POM_DESCRIPTION=Solid is an Android library, which provides lightweight data streams and immutable+parcelable collections. 6 | POM_URL=https://github.com/konmik/solid 7 | POM_SCM_URL=https://github.com/konmik/solid 8 | POM_SCM_CONNECTION=scm:git@github.com:konmik/solid.git 9 | POM_SCM_DEV_CONNECTION=scm:git@github.com:konimk/solid.git 10 | POM_LICENCE_NAME=MIT 11 | POM_LICENCE_URL=http://opensource.org/licenses/MIT 12 | POM_LICENCE_DIST=repo 13 | POM_DEVELOPER_ID=sirstripy 14 | POM_DEVELOPER_NAME=Konstantin Mikheev 15 | 16 | #RELEASE_REPOSITORY_URL=file://C:/Users/konmik/.m2/repository 17 | #SNAPSHOT_REPOSITORY_URL=file://C:/Users/konmik/.m2/repository 18 | -------------------------------------------------------------------------------- /gradle/gradle-mvn-push.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Chris Banes 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'maven' 18 | apply plugin: 'signing' 19 | 20 | def isReleaseBuild() { 21 | return VERSION_NAME.contains("SNAPSHOT") == false 22 | } 23 | 24 | def getReleaseRepositoryUrl() { 25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL 26 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 27 | } 28 | 29 | def getSnapshotRepositoryUrl() { 30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL 31 | : "https://oss.sonatype.org/content/repositories/snapshots/" 32 | } 33 | 34 | def getRepositoryUsername() { 35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" 36 | } 37 | 38 | def getRepositoryPassword() { 39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" 40 | } 41 | 42 | afterEvaluate { project -> 43 | uploadArchives { 44 | repositories { 45 | mavenDeployer { 46 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 47 | 48 | pom.groupId = GROUP 49 | pom.artifactId = POM_ARTIFACT_ID 50 | pom.version = VERSION_NAME 51 | 52 | repository(url: getReleaseRepositoryUrl()) { 53 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 54 | } 55 | snapshotRepository(url: getSnapshotRepositoryUrl()) { 56 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 57 | } 58 | 59 | pom.project { 60 | name POM_NAME 61 | packaging POM_PACKAGING 62 | description POM_DESCRIPTION 63 | url POM_URL 64 | 65 | scm { 66 | url POM_SCM_URL 67 | connection POM_SCM_CONNECTION 68 | developerConnection POM_SCM_DEV_CONNECTION 69 | } 70 | 71 | licenses { 72 | license { 73 | name POM_LICENCE_NAME 74 | url POM_LICENCE_URL 75 | distribution POM_LICENCE_DIST 76 | } 77 | } 78 | 79 | developers { 80 | developer { 81 | id POM_DEVELOPER_ID 82 | name POM_DEVELOPER_NAME 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | 90 | signing { 91 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } 92 | sign configurations.archives 93 | } 94 | 95 | task androidJavadocs(type: Javadoc) { 96 | failOnError false 97 | source = android.sourceSets.main.java.srcDirs 98 | classpath += project.files(android.getBootClasspath()) + project.files(configurations.compileJavadoc) 99 | } 100 | 101 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { 102 | classifier = 'javadoc' 103 | from androidJavadocs.destinationDir 104 | } 105 | 106 | task androidSourcesJar(type: Jar) { 107 | classifier = 'sources' 108 | from android.sourceSets.main.java.sourceFiles 109 | } 110 | 111 | artifacts { 112 | archives androidSourcesJar 113 | archives androidJavadocsJar 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konmik/solid/3d6c452ef3219fd843547f3590b3d2e1ad3f1d17/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /java7test/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /java7test/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 15 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | } 14 | 15 | repositories { 16 | mavenLocal() 17 | } 18 | 19 | dependencies { 20 | testCompile 'junit:junit:4.12' 21 | testCompile project(':streams') 22 | testCompile project(':collections') 23 | } 24 | -------------------------------------------------------------------------------- /java7test/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /java7test/src/test/java/solid/stream/StreamDemo.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Comparator; 7 | 8 | import solid.collections.Grouped; 9 | import solid.collections.Indexed; 10 | import solid.collectors.ToArrayList; 11 | import solid.collectors.ToList; 12 | import solid.functions.Action1; 13 | import solid.functions.Func1; 14 | import solid.functions.Func2; 15 | 16 | import static java.util.Arrays.asList; 17 | import static java.util.Collections.emptyList; 18 | import static java.util.Collections.singletonList; 19 | import static org.junit.Assert.assertArrayEquals; 20 | import static org.junit.Assert.assertEquals; 21 | import static solid.collectors.ToArray.toArray; 22 | import static solid.collectors.ToArrays.toBytes; 23 | import static solid.collectors.ToArrays.toDoubles; 24 | import static solid.collectors.ToArrays.toFloats; 25 | import static solid.collectors.ToArrays.toInts; 26 | import static solid.collectors.ToArrays.toLongs; 27 | import static solid.collectors.ToJoinedString.toJoinedString; 28 | import static solid.stream.Stream.of; 29 | import static test_utils.AssertIterableEquals.assertGroupedEquals; 30 | import static test_utils.AssertIterableEquals.assertIterableEquals; 31 | 32 | public class StreamDemo { 33 | 34 | @Test 35 | public void construction() throws Exception { 36 | 37 | // Stream.of() 38 | // an empty stream 39 | 40 | assertIterableEquals(emptyList(), 41 | Stream.of()); 42 | 43 | // Stream.of(value) 44 | // a stream of one value 45 | 46 | assertIterableEquals(singletonList(1), 47 | Stream.of(1)); 48 | 49 | // Stream.of(values) 50 | // a stream of given values 51 | 52 | assertIterableEquals(asList(1, 2, 3), 53 | Stream.of(1, 2, 3)); 54 | 55 | // Stream.stream(array) 56 | // a stream of array values 57 | 58 | assertIterableEquals(asList(1, 2, 3), 59 | Stream.stream(new Integer[]{1, 2, 3})); 60 | 61 | // Stream.stream(iterable) 62 | // a stream of iterable values 63 | 64 | assertIterableEquals(asList(1, 2, 3), 65 | Stream.stream(asList(1, 2, 3))); 66 | } 67 | 68 | @Test 69 | public void basic_operators() throws Exception { 70 | 71 | // Stream.first() 72 | // returns only the first value (as Optional) 73 | 74 | assertEquals((Integer) 1, 75 | Stream.of(1, 2, 3) 76 | .first() 77 | .get()); 78 | 79 | // Stream.last() 80 | // returns only the last one value (as Optional) 81 | 82 | assertEquals((Integer) 3, 83 | Stream.of(1, 2, 3) 84 | .last() 85 | .get()); 86 | 87 | // Stream.filter(condition) 88 | // skips all items that do not satisfy a given condition 89 | 90 | assertIterableEquals(asList(1, 2), 91 | Stream.of(1, 2, 3) 92 | .filter(new Func1() { 93 | @Override 94 | public Boolean call(Integer it) { 95 | return it < 3; 96 | } 97 | })); 98 | 99 | // Stream.map 100 | // transforms each item 101 | 102 | assertIterableEquals(asList("1", "2", "3"), 103 | Stream.of(1, 2, 3) 104 | .map(new Func1() { 105 | @Override 106 | public String call(Integer it) { 107 | return it.toString(); 108 | } 109 | })); 110 | } 111 | 112 | @Test 113 | public void control_operators() throws Exception { 114 | 115 | // Stream.merge(item) 116 | // adds an item to the end 117 | 118 | assertIterableEquals(asList(1, 2, 3), 119 | Stream.of(1, 2) 120 | .merge(3)); 121 | 122 | // Stream.merge(stream) 123 | // adds a stream to the end 124 | 125 | assertIterableEquals(asList(1, 2, 3), 126 | Stream.of(1) 127 | .merge(Stream.of(2, 3))); 128 | 129 | // Stream.separate(item) 130 | // removes an item 131 | 132 | assertIterableEquals(asList(1, 2, 3), 133 | Stream.of(1, 2, 3, 4) 134 | .separate(4)); 135 | 136 | // Stream.separate(stream) 137 | // removes all items of a given stream 138 | 139 | assertIterableEquals(asList(1, 2, 3), 140 | Stream.of(1, 2, 3, 4, 5) 141 | .separate(Stream.of(4, 5))); 142 | 143 | // Stream.take(x) 144 | // takes only the first x items 145 | 146 | assertIterableEquals(asList(1, 2, 3), 147 | Stream.of(1, 2, 3, 4) 148 | .take(3)); 149 | 150 | // Stream.skip(x) 151 | // skips first x items 152 | 153 | assertIterableEquals(asList(1, 2, 3), 154 | Stream.of(-1, 0, 1, 2, 3) 155 | .skip(2)); 156 | 157 | // Stream.distinct() 158 | // skips duplicate items 159 | 160 | assertIterableEquals(asList(1, 2, 3), 161 | Stream.of(1, 1, 2, 3, 3) 162 | .distinct()); 163 | 164 | // Stream.reverse() 165 | // reverses item order 166 | 167 | assertIterableEquals(asList(1, 2, 3), 168 | Stream.of(3, 2, 1) 169 | .reverse()); 170 | 171 | // Stream.sort(comparator) 172 | // sorts items 173 | 174 | assertIterableEquals(asList(1, 2, 3), 175 | Stream.of(2, 1, 3) 176 | .sort(new Comparator() { 177 | @Override 178 | public int compare(Integer lhs, Integer rhs) { 179 | return lhs.compareTo(rhs); 180 | } 181 | })); 182 | } 183 | 184 | @Test 185 | public void advanced_operators() throws Exception { 186 | 187 | // Stream.reduce(accumulator) 188 | // accumulates values using an accumulating function 189 | 190 | assertEquals((Integer) 6, 191 | Stream.of(1, 2, 3) 192 | .reduce(new Func2() { 193 | @Override 194 | public Integer call(Integer x, Integer y) { 195 | return x + y; 196 | } 197 | }) 198 | .get()); 199 | 200 | // Stream.reduce(initial value, accumulator) 201 | // accumulates values using an initial value and an accumulating function 202 | 203 | assertEquals((Integer) 16, 204 | Stream.of(1, 2, 3) 205 | .reduce(10, new Func2() { 206 | @Override 207 | public Integer call(Integer x, Integer y) { 208 | return x + y; 209 | } 210 | })); 211 | 212 | // Stream.flatMap(stream generator) 213 | // replaces each item with set of items 214 | 215 | assertIterableEquals(asList(100, 1, 200, 2, 300, 3), 216 | Stream.of(1, 2, 3) 217 | .flatMap(new Func1>() { 218 | @Override 219 | public Iterable call(Integer it) { 220 | return Stream.of(it * 100, it); 221 | } 222 | })); 223 | 224 | // Stream.groupBy(group selector) 225 | // groups items using a group selector 226 | 227 | assertGroupedEquals(asList(new Grouped<>(0, Stream.of(1, 3)), new Grouped<>(10, Stream.of(12, 13))), 228 | Stream.of(1, 12, 3, 13) 229 | .groupBy(new Func1() { 230 | @Override 231 | public Integer call(Integer value) { 232 | return value - value % 10; 233 | } 234 | })); 235 | 236 | // Stream.groupBy(group selector) 237 | // groups items using a group and a value selectors 238 | 239 | assertGroupedEquals(asList(new Grouped<>(0, Stream.of(1, 3)), new Grouped<>(10, Stream.of(2, 3))), 240 | Stream.of(1, 12, 3, 13) 241 | .groupBy(new Func1() { 242 | @Override 243 | public Integer call(Integer value) { 244 | return value - value % 10; 245 | } 246 | }, new Func1() { 247 | @Override 248 | public Integer call(Integer value) { 249 | return value % 10; 250 | } 251 | })); 252 | } 253 | 254 | @Test 255 | public void utility_operators() throws Exception { 256 | 257 | // Stream.index() 258 | // Indexes each value 259 | 260 | assertIterableEquals(asList(new Indexed<>(0, "1"), new Indexed<>(1, "2"), new Indexed<>(2, "3")), 261 | Stream.of("1", "2", "3") 262 | .index()); 263 | } 264 | 265 | @Test 266 | public void side_effects() throws Exception { 267 | final ArrayList out = new ArrayList<>(); 268 | final ArrayList out2 = new ArrayList<>(); 269 | 270 | // Stream.forEach 271 | // feeds items to a consuming function 272 | 273 | Stream.of(1, 2, 3) 274 | .forEach(new Action1() { 275 | @Override 276 | public void call(Integer it) { 277 | out.add(it); 278 | } 279 | }); 280 | assertIterableEquals(asList(1, 2, 3), out); 281 | 282 | // Stream.onNext 283 | // feeds items to a consuming functions during lazy evaluation 284 | 285 | Stream.of(1, 2, 3, 4, 5) 286 | .onNext(new Action1() { 287 | @Override 288 | public void call(Integer it) { 289 | out2.add(it); 290 | } 291 | }) 292 | .take(3) 293 | .last(); 294 | assertIterableEquals(asList(1, 2, 3), out2); 295 | } 296 | 297 | @Test 298 | public void collectors() throws Exception { 299 | 300 | // Stream.collect(custom collector) 301 | // transforms into another data structure 302 | 303 | assertEquals(asList(1, 2, 3), Stream.of(1, 2, 3).collect(new Func1, ArrayList>() { 304 | @Override 305 | public ArrayList call(Iterable it) { 306 | ArrayList list = new ArrayList<>(); 307 | for (int i : it) 308 | list.add(i); 309 | return list; 310 | } 311 | })); 312 | 313 | // toList() 314 | // collects into List 315 | 316 | assertEquals(asList(1, 2, 3), 317 | Stream.of(1, 2, 3) 318 | .collect(ToList.toList())); 319 | 320 | // toArrayList() 321 | // collects into ArrayList 322 | 323 | assertEquals(asList(1, 2, 3), 324 | Stream.of(1, 2, 3) 325 | .collect(ToArrayList.toArrayList())); 326 | 327 | 328 | // toArray(Class) 329 | // collects into an Array 330 | 331 | assertArrayEquals(new Integer[]{1, 2, 3}, 332 | of(1, 2, 3) 333 | .collect(toArray(Integer.class))); 334 | 335 | // toJoinedString() 336 | // joins strings 337 | assertEquals("123", 338 | Stream.of("1", "2", "3") 339 | .collect(toJoinedString())); 340 | 341 | // toJoinedString(delimiter) 342 | // joins strings with a delimiter 343 | 344 | assertEquals("1, 2, 3", 345 | Stream.of("1", "2", "3") 346 | .collect(toJoinedString(", "))); 347 | } 348 | 349 | @Test 350 | public void primitive_arrays() throws Exception { 351 | 352 | // Primitives.box(primitive array) 353 | // boxes primitive array items 354 | 355 | assertIterableEquals(asList(1, 2, 3), 356 | Primitives.box(new int[]{1, 2, 3})); 357 | 358 | assertIterableEquals(asList(1L, 2L, 3L), 359 | Primitives.box(new long[]{1, 2, 3})); 360 | 361 | assertIterableEquals(asList(1f, 2f, 3f), 362 | Primitives.box(new float[]{1, 2, 3})); 363 | 364 | assertIterableEquals(asList(new Byte[]{1, 2, 3}), 365 | Primitives.box(new byte[]{1, 2, 3})); 366 | 367 | assertIterableEquals(asList(1., 2., 3.), 368 | Primitives.box(new double[]{1, 2, 3})); 369 | 370 | // ToArrays.toInts, toLongs, toFloats, toBytes, toDoubles 371 | // unboxes a primitive array 372 | 373 | assertArrayEquals(new int[]{1, 2, 3}, 374 | Stream.of(1, 2, 3) 375 | .collect(toInts())); 376 | 377 | assertArrayEquals(new long[]{1L, 2L, 3L}, 378 | Stream.of(1L, 2L, 3L) 379 | .collect(toLongs())); 380 | 381 | assertArrayEquals(new float[]{1, 2, 3}, 382 | Stream.of(1f, 2f, 3f) 383 | .collect(toFloats()), 0); 384 | 385 | assertArrayEquals(new byte[]{1, 2, 3}, 386 | Stream.of(new Byte[]{1, 2, 3}) 387 | .collect(toBytes())); 388 | 389 | assertArrayEquals(new double[]{1, 2, 3}, 390 | Stream.of(1., 2., 3.) 391 | .collect(toDoubles()), 0); 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /java7test/src/test/java/test_utils/AssertIterableEquals.java: -------------------------------------------------------------------------------- 1 | package test_utils; 2 | 3 | import java.util.Iterator; 4 | 5 | import solid.collections.Grouped; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | import static org.junit.Assert.assertFalse; 9 | 10 | public class AssertIterableEquals { 11 | public static void assertIterableEquals(Iterable iterable1, Iterable iterable2) { 12 | Iterator iterator1 = iterable1.iterator(); 13 | Iterator iterator2 = iterable2.iterator(); 14 | while (iterator1.hasNext() && iterator2.hasNext()) 15 | assertEquals(iterator1.next(), iterator2.next()); 16 | assertFalse(iterator1.hasNext()); 17 | assertFalse(iterator2.hasNext()); 18 | } 19 | 20 | public static void assertGroupedEquals(Iterable iterable1, Iterable iterable2) { 21 | Iterator iterator1 = iterable1.iterator(); 22 | Iterator iterator2 = iterable2.iterator(); 23 | while (iterator1.hasNext() && iterator2.hasNext()) { 24 | T next1 = iterator1.next(); 25 | T next2 = iterator2.next(); 26 | assertEquals(next1.group, next2.group); 27 | assertIterableEquals(next1.stream, next2.stream); 28 | } 29 | assertFalse(iterator1.hasNext()); 30 | assertFalse(iterator2.hasNext()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /retrolambdatest/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /retrolambdatest/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | 14 | compileOptions { 15 | sourceCompatibility JavaVersion.VERSION_1_8 16 | targetCompatibility JavaVersion.VERSION_1_8 17 | } 18 | } 19 | 20 | buildscript { 21 | repositories { 22 | mavenCentral() 23 | } 24 | 25 | dependencies { 26 | classpath 'me.tatarka:gradle-retrolambda:3.2.4' 27 | } 28 | } 29 | 30 | repositories { 31 | mavenLocal() 32 | } 33 | 34 | apply plugin: 'me.tatarka.retrolambda' 35 | 36 | dependencies { 37 | testCompile 'junit:junit:4.12' 38 | testCompile project(':streams') 39 | testCompile project(':collections') 40 | } 41 | -------------------------------------------------------------------------------- /retrolambdatest/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /retrolambdatest/src/test/java/solid/stream/StreamDemo.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | 7 | import solid.collections.Grouped; 8 | import solid.collections.Indexed; 9 | 10 | import static java.util.Arrays.asList; 11 | import static java.util.Collections.emptyList; 12 | import static java.util.Collections.singletonList; 13 | import static org.junit.Assert.assertArrayEquals; 14 | import static org.junit.Assert.assertEquals; 15 | import static solid.collectors.ToArray.toArray; 16 | import static solid.collectors.ToArrayList.toArrayList; 17 | import static solid.collectors.ToArrays.toBytes; 18 | import static solid.collectors.ToArrays.toDoubles; 19 | import static solid.collectors.ToArrays.toFloats; 20 | import static solid.collectors.ToArrays.toInts; 21 | import static solid.collectors.ToArrays.toLongs; 22 | import static solid.collectors.ToJoinedString.toJoinedString; 23 | import static solid.collectors.ToList.toList; 24 | import static solid.stream.Primitives.box; 25 | import static solid.stream.Stream.of; 26 | import static test_utils.AssertIterableEquals.assertGroupedEquals; 27 | import static test_utils.AssertIterableEquals.assertIterableEquals; 28 | 29 | public class StreamDemo { 30 | 31 | @Test 32 | public void construction() throws Exception { 33 | 34 | // Stream.of() 35 | // an empty stream 36 | 37 | assertIterableEquals(emptyList(), 38 | of()); 39 | 40 | // Stream.of(value) 41 | // a stream of one value 42 | 43 | assertIterableEquals(singletonList(1), 44 | of(1)); 45 | 46 | // Stream.of(values) 47 | // a stream of given values 48 | 49 | assertIterableEquals(asList(1, 2, 3), 50 | of(1, 2, 3)); 51 | 52 | // Stream.stream(array) 53 | // a stream of array values 54 | 55 | assertIterableEquals(asList(1, 2, 3), 56 | Stream.stream(new Integer[]{1, 2, 3})); 57 | 58 | // Stream.stream(iterable) 59 | // a stream of iterable values 60 | 61 | assertIterableEquals(asList(1, 2, 3), 62 | Stream.stream(asList(1, 2, 3))); 63 | } 64 | 65 | @Test 66 | public void basic_operators() throws Exception { 67 | 68 | // Stream.first() 69 | // returns only the first value (as Optional) 70 | 71 | assertEquals((Integer) 1, 72 | of(1, 2, 3) 73 | .first() 74 | .get()); 75 | 76 | // Stream.last() 77 | // returns only the last one value (as Optional) 78 | 79 | assertEquals((Integer) 3, 80 | of(1, 2, 3) 81 | .last() 82 | .get()); 83 | 84 | // Stream.filter(condition) 85 | // skips all items that do not satisfy a given condition 86 | 87 | assertIterableEquals(asList(1, 2), 88 | of(1, 2, 3) 89 | .filter(it -> it < 3)); 90 | 91 | // Stream.map 92 | // transforms each item 93 | 94 | assertIterableEquals(asList("1", "2", "3"), 95 | of(1, 2, 3) 96 | .map(it -> it.toString())); 97 | } 98 | 99 | @Test 100 | public void control_operators() throws Exception { 101 | 102 | // Stream.merge(item) 103 | // adds an item to the end 104 | 105 | assertIterableEquals(asList(1, 2, 3), 106 | of(1, 2) 107 | .merge(3)); 108 | 109 | // Stream.merge(stream) 110 | // adds a stream to the end 111 | 112 | assertIterableEquals(asList(1, 2, 3), 113 | of(1) 114 | .merge(of(2, 3))); 115 | 116 | // Stream.separate(item) 117 | // removes an item 118 | 119 | assertIterableEquals(asList(1, 2, 3), 120 | of(1, 2, 3, 4) 121 | .separate(4)); 122 | 123 | // Stream.separate(stream) 124 | // removes all items of a given stream 125 | 126 | assertIterableEquals(asList(1, 2, 3), 127 | of(1, 2, 3, 4, 5) 128 | .separate(of(4, 5))); 129 | 130 | // Stream.take(x) 131 | // takes only the first x items 132 | 133 | assertIterableEquals(asList(1, 2, 3), 134 | of(1, 2, 3, 4) 135 | .take(3)); 136 | 137 | // Stream.skip(x) 138 | // skips first x items 139 | 140 | assertIterableEquals(asList(1, 2, 3), 141 | of(-1, 0, 1, 2, 3) 142 | .skip(2)); 143 | 144 | // Stream.distinct() 145 | // skips duplicate items 146 | 147 | assertIterableEquals(asList(1, 2, 3), 148 | of(1, 1, 2, 3, 3) 149 | .distinct()); 150 | 151 | // Stream.reverse() 152 | // reverses item order 153 | 154 | assertIterableEquals(asList(1, 2, 3), 155 | of(3, 2, 1) 156 | .reverse()); 157 | 158 | // Stream.sort(comparator) 159 | // sorts items 160 | 161 | assertIterableEquals(asList(1, 2, 3), 162 | of(2, 1, 3) 163 | .sort(Integer::compareTo)); 164 | } 165 | 166 | @Test 167 | public void advanced_operators() throws Exception { 168 | 169 | // Stream.reduce(accumulator) 170 | // accumulates values using an accumulating function 171 | 172 | assertEquals((Integer) 6, 173 | of(1, 2, 3) 174 | .reduce((x, y) -> x + y) 175 | .get()); 176 | 177 | // Stream.reduce(initial value, accumulator) 178 | // accumulates values using an initial value and an accumulating function 179 | 180 | assertEquals((Integer) 16, 181 | of(1, 2, 3) 182 | .reduce(10, (x, y) -> x + y)); 183 | 184 | // Stream.flatMap(stream generator) 185 | // replaces each item with set of items 186 | 187 | assertIterableEquals(asList(100, 1, 200, 2, 300, 3), 188 | of(1, 2, 3) 189 | .flatMap(it -> of(it * 100, it))); 190 | 191 | // Stream.groupBy(group selector) 192 | // groups items using a group selector 193 | 194 | assertGroupedEquals(asList(new Grouped<>(0, of(1, 3)), new Grouped<>(10, of(12, 13))), 195 | of(1, 12, 3, 13) 196 | .groupBy(value -> value - value % 10)); 197 | 198 | // Stream.groupBy(group selector, value selector) 199 | // groups items using a group and a value selectors 200 | 201 | assertGroupedEquals(asList(new Grouped<>(0, of(1, 3)), new Grouped<>(10, of(2, 3))), 202 | of(1, 12, 3, 13) 203 | .groupBy(value -> value - value % 10, value -> value % 10)); 204 | } 205 | 206 | @Test 207 | public void utility_operators() throws Exception { 208 | 209 | // Stream.index() 210 | // Indexes each value 211 | 212 | assertIterableEquals(asList(new Indexed<>(0, "1"), new Indexed<>(1, "2"), new Indexed<>(2, "3")), 213 | of("1", "2", "3") 214 | .index()); 215 | } 216 | 217 | @Test 218 | public void side_effects() throws Exception { 219 | ArrayList out = new ArrayList<>(); 220 | ArrayList out2 = new ArrayList<>(); 221 | 222 | // Stream.forEach 223 | // feeds items to a consuming function 224 | 225 | of(1, 2, 3) 226 | .forEach(it -> out.add(it)); 227 | assertIterableEquals(asList(1, 2, 3), out); 228 | 229 | // Stream.onNext 230 | // feeds items to a consuming functions during lazy evaluation 231 | 232 | of(1, 2, 3, 4, 5) 233 | .onNext(it -> out2.add(it)) 234 | .take(3) 235 | .last(); 236 | assertIterableEquals(asList(1, 2, 3), out2); 237 | } 238 | 239 | @Test 240 | public void collectors() throws Exception { 241 | 242 | // Stream.collect(custom collector) 243 | // transforms into another data structure 244 | 245 | assertEquals(asList(1, 2, 3), of(1, 2, 3).collect(it -> { 246 | ArrayList list = new ArrayList<>(); 247 | for (int i : it) 248 | list.add(i); 249 | return list; 250 | })); 251 | 252 | // toList() 253 | // collects into List 254 | 255 | assertEquals(asList(1, 2, 3), 256 | of(1, 2, 3) 257 | .collect(toList())); 258 | 259 | // toArrayList() 260 | // collects into ArrayList 261 | 262 | assertEquals(asList(1, 2, 3), 263 | of(1, 2, 3) 264 | .collect(toArrayList())); 265 | 266 | // toArray(Class) 267 | // collects into an Array 268 | 269 | assertArrayEquals(new Integer[]{1, 2, 3}, 270 | of(1, 2, 3) 271 | .collect(toArray(Integer.class))); 272 | 273 | // toJoinedString() 274 | // joins strings 275 | 276 | assertEquals("123", 277 | of("1", "2", "3") 278 | .collect(toJoinedString())); 279 | 280 | // toJoinedString(delimiter) 281 | // joins strings with a delimiter 282 | 283 | assertEquals("1, 2, 3", 284 | of("1", "2", "3") 285 | .collect(toJoinedString(", "))); 286 | } 287 | 288 | @Test 289 | public void primitive_arrays() throws Exception { 290 | 291 | // Primitives.box(primitive array) 292 | // boxes primitive array items 293 | 294 | assertIterableEquals(asList(1, 2, 3), 295 | box(new int[]{1, 2, 3})); 296 | 297 | assertIterableEquals(asList(1L, 2L, 3L), 298 | box(new long[]{1, 2, 3})); 299 | 300 | assertIterableEquals(asList(1f, 2f, 3f), 301 | box(new float[]{1, 2, 3})); 302 | 303 | assertIterableEquals(asList(new Byte[]{1, 2, 3}), 304 | box(new byte[]{1, 2, 3})); 305 | 306 | assertIterableEquals(asList(1., 2., 3.), 307 | box(new double[]{1, 2, 3})); 308 | 309 | // ToArrays.toInts, toLongs, toFloats, toBytes, toDoubles 310 | // unboxes a primitive array 311 | 312 | assertArrayEquals(new int[]{1, 2, 3}, 313 | of(1, 2, 3) 314 | .collect(toInts())); 315 | 316 | assertArrayEquals(new long[]{1L, 2L, 3L}, 317 | of(1L, 2L, 3L) 318 | .collect(toLongs())); 319 | 320 | assertArrayEquals(new float[]{1, 2, 3}, 321 | of(1f, 2f, 3f) 322 | .collect(toFloats()), 0); 323 | 324 | assertArrayEquals(new byte[]{1, 2, 3}, 325 | of(new Byte[]{1, 2, 3}) 326 | .collect(toBytes())); 327 | 328 | assertArrayEquals(new double[]{1, 2, 3}, 329 | of(1., 2., 3.) 330 | .collect(toDoubles()), 331 | 0); 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /retrolambdatest/src/test/java/test_utils/AssertIterableEquals.java: -------------------------------------------------------------------------------- 1 | package test_utils; 2 | 3 | import java.util.Iterator; 4 | 5 | import solid.collections.Grouped; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | import static org.junit.Assert.assertFalse; 9 | 10 | public class AssertIterableEquals { 11 | public static void assertIterableEquals(Iterable iterable1, Iterable iterable2) { 12 | Iterator iterator1 = iterable1.iterator(); 13 | Iterator iterator2 = iterable2.iterator(); 14 | while (iterator1.hasNext() && iterator2.hasNext()) 15 | assertEquals(iterator1.next(), iterator2.next()); 16 | assertFalse(iterator1.hasNext()); 17 | assertFalse(iterator2.hasNext()); 18 | } 19 | 20 | public static void assertGroupedEquals(Iterable iterable1, Iterable iterable2) { 21 | Iterator iterator1 = iterable1.iterator(); 22 | Iterator iterator2 = iterable2.iterator(); 23 | while (iterator1.hasNext() && iterator2.hasNext()) { 24 | T next1 = iterator1.next(); 25 | T next2 = iterator2.next(); 26 | assertEquals(next1.group, next2.group); 27 | assertIterableEquals(next1.stream, next2.stream); 28 | } 29 | assertFalse(iterator1.hasNext()); 30 | assertFalse(iterator2.hasNext()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':streams', ':collections', ':retrolambdatest', ':java7test' 2 | -------------------------------------------------------------------------------- /streams/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /streams/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 10 9 | targetSdkVersion 22 10 | versionCode 2 11 | versionName "1.0.1" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | } 15 | 16 | configurations { 17 | compileJavadoc 18 | } 19 | 20 | dependencies { 21 | androidTestCompile 'junit:junit:4.12' 22 | androidTestCompile 'com.android.support.test:runner:0.3' 23 | 24 | testCompile 'junit:junit:4.12' 25 | testCompile 'org.mockito:mockito-core:2.0.12-beta' 26 | } 27 | 28 | android.libraryVariants.all { variant -> 29 | def name = variant.buildType.name 30 | if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) { 31 | return; // Skip debug builds. 32 | } 33 | def task = project.tasks.create "jar${name.capitalize()}", Jar 34 | task.dependsOn variant.javaCompile 35 | task.from variant.javaCompile.destinationDir 36 | artifacts.add('archives', task); 37 | } 38 | 39 | apply from: '../gradle/gradle-mvn-push.gradle' 40 | -------------------------------------------------------------------------------- /streams/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Solid 2 | POM_ARTIFACT_ID=streams 3 | POM_PACKAGING=jar 4 | -------------------------------------------------------------------------------- /streams/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/collections/Grouped.java: -------------------------------------------------------------------------------- 1 | package solid.collections; 2 | 3 | import solid.stream.Stream; 4 | 5 | /** 6 | * Group - list pair. 7 | */ 8 | public class Grouped { 9 | 10 | public final G group; 11 | public final Stream stream; 12 | 13 | public Grouped(G group, Stream stream) { 14 | this.group = group; 15 | this.stream = stream; 16 | } 17 | 18 | @Override 19 | public boolean equals(Object o) { 20 | if (this == o) return true; 21 | if (o == null || getClass() != o.getClass()) return false; 22 | 23 | Grouped grouped = (Grouped) o; 24 | 25 | if (group != null ? !group.equals(grouped.group) : grouped.group != null) return false; 26 | return !(stream != null ? !stream.equals(grouped.stream) : grouped.stream != null); 27 | } 28 | 29 | @Override 30 | public int hashCode() { 31 | int result = group != null ? group.hashCode() : 0; 32 | result = 31 * result + (stream != null ? stream.hashCode() : 0); 33 | return result; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "Grouped{" + 39 | "group=" + group + 40 | ", list=" + stream + 41 | '}'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/collections/Indexed.java: -------------------------------------------------------------------------------- 1 | package solid.collections; 2 | 3 | /** 4 | * Index - value pair. 5 | */ 6 | public class Indexed { 7 | 8 | public final int index; 9 | public final T value; 10 | 11 | public Indexed(int index, T value) { 12 | this.index = index; 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public boolean equals(Object o) { 18 | if (this == o) return true; 19 | if (o == null || getClass() != o.getClass()) return false; 20 | 21 | Indexed indexed = (Indexed) o; 22 | 23 | if (index != indexed.index) return false; 24 | return !(value != null ? !value.equals(indexed.value) : indexed.value != null); 25 | } 26 | 27 | @Override 28 | public int hashCode() { 29 | int result = value != null ? value.hashCode() : 0; 30 | result = 31 * result + index; 31 | return result; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "Indexed{" + 37 | "value=" + value + 38 | ", index=" + index + 39 | '}'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/collections/Pair.java: -------------------------------------------------------------------------------- 1 | package solid.collections; 2 | 3 | /** 4 | * This is a duplicate of {@link android.util.Pair} but without Android SDK requirement. 5 | */ 6 | public class Pair { 7 | 8 | public final T1 first; 9 | public final T2 second; 10 | 11 | public Pair(T1 first, T2 second) { 12 | this.first = first; 13 | this.second = second; 14 | } 15 | 16 | @Override 17 | public boolean equals(Object o) { 18 | if (this == o) return true; 19 | if (o == null || getClass() != o.getClass()) return false; 20 | 21 | Pair pair = (Pair) o; 22 | 23 | if (first != null ? !first.equals(pair.first) : pair.first != null) return false; 24 | return !(second != null ? !second.equals(pair.second) : pair.second != null); 25 | } 26 | 27 | @Override 28 | public int hashCode() { 29 | int result = first != null ? first.hashCode() : 0; 30 | result = 31 * result + (second != null ? second.hashCode() : 0); 31 | return result; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "Pair{" + 37 | "first=" + first + 38 | ", second=" + second + 39 | '}'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/collectors/ToArray.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.ArrayList; 5 | 6 | import solid.functions.Func1; 7 | 8 | public class ToArray { 9 | 10 | public static Func1, T[]> toArray(final Class cls) { 11 | return new Func1, T[]>() { 12 | @Override 13 | public T[] call(Iterable value) { 14 | ArrayList list = ToArrayList.toArrayList().call(value); 15 | return list.toArray((T[]) Array.newInstance(cls, list.size())); 16 | } 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/collectors/ToArrayList.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import solid.functions.Func1; 7 | 8 | public class ToArrayList { 9 | 10 | private static final Func1 TO_ARRAY_LIST = toArrayList(0); 11 | 12 | /** 13 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 14 | * to convert a stream into a {@link ArrayList}. 15 | * 16 | * @param a type of {@link ArrayList} items. 17 | * @return a method that converts an iterable into {@link ArrayList}. 18 | */ 19 | public static Func1, ArrayList> toArrayList() { 20 | return TO_ARRAY_LIST; 21 | } 22 | 23 | /** 24 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 25 | * to convert a stream into a {@link List}. 26 | *

27 | * Use this method instead of {@link #toArrayList()} for better performance on 28 | * streams that can have more than 12 items. 29 | * 30 | * @param a type of {@link List} items. 31 | * @param initialCapacity initial capacity of the list. 32 | * @return a method that converts an iterable into {@link List}. 33 | */ 34 | public static Func1, ArrayList> toArrayList(final int initialCapacity) { 35 | return new Func1, ArrayList>() { 36 | @Override 37 | public ArrayList call(Iterable iterable) { 38 | ArrayList list = new ArrayList<>(initialCapacity); 39 | for (T value : iterable) 40 | list.add(value); 41 | return list; 42 | } 43 | }; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/collectors/ToArrays.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import java.util.Arrays; 4 | 5 | import solid.functions.Func1; 6 | 7 | public class ToArrays { 8 | 9 | /** 10 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 11 | * to convert an iterable stream of {@link Number} type into a primitive byte[] array. 12 | * 13 | * @return a method that converts an iterable stream of {@link Number} type into a primitive byte[] array. 14 | */ 15 | public static Func1, byte[]> toBytes() { 16 | return new Func1, byte[]>() { 17 | @Override 18 | public byte[] call(Iterable value) { 19 | return new QuickNumberArray(value).toBytes(); 20 | } 21 | }; 22 | } 23 | 24 | /** 25 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 26 | * to convert an iterable stream of {@link Number} type into a primitive double[] array. 27 | * 28 | * @return a method that converts an iterable stream of {@link Number} type into a primitive double[] array. 29 | */ 30 | public static Func1, double[]> toDoubles() { 31 | return new Func1, double[]>() { 32 | @Override 33 | public double[] call(Iterable value) { 34 | return new QuickNumberArray(value).toDoubles(); 35 | } 36 | }; 37 | } 38 | 39 | /** 40 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 41 | * to convert an iterable stream of {@link Number} type into a primitive float[] array. 42 | * 43 | * @return a method that converts an iterable stream of {@link Number} type into a primitive float[] array. 44 | */ 45 | public static Func1, float[]> toFloats() { 46 | return new Func1, float[]>() { 47 | @Override 48 | public float[] call(Iterable value) { 49 | return new QuickNumberArray(value).toFloats(); 50 | } 51 | }; 52 | } 53 | 54 | /** 55 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 56 | * to convert an iterable stream of {@link Number} type into a primitive int[] array. 57 | * 58 | * @return a method that converts an iterable stream of {@link Number} type into a primitive int[] array. 59 | */ 60 | public static Func1, int[]> toInts() { 61 | return new Func1, int[]>() { 62 | @Override 63 | public int[] call(Iterable value) { 64 | return new QuickNumberArray(value).toInts(); 65 | } 66 | }; 67 | } 68 | 69 | /** 70 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 71 | * to convert an iterable stream of {@link Number} type into a primitive long[] array. 72 | * 73 | * @return a method that converts an iterable stream of {@link Number} type into a primitive long[] array. 74 | */ 75 | public static Func1, long[]> toLongs() { 76 | return new Func1, long[]>() { 77 | @Override 78 | public long[] call(Iterable value) { 79 | return new QuickNumberArray(value).toLongs(); 80 | } 81 | }; 82 | } 83 | 84 | /** 85 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 86 | * to convert an iterable stream of {@link Number} type into a primitive short[] array. 87 | * 88 | * @return a method that converts an iterable stream of {@link Number} type into a primitive short[] array. 89 | */ 90 | public static Func1, short[]> toShorts() { 91 | return new Func1, short[]>() { 92 | @Override 93 | public short[] call(Iterable value) { 94 | return new QuickNumberArray(value).toShorts(); 95 | } 96 | }; 97 | } 98 | 99 | private static final Number[] EMPTY_ARRAY = new Number[0]; 100 | private static final int MIN_CAPACITY_INCREMENT = 12; 101 | 102 | private static class QuickNumberArray { 103 | 104 | private Number[] array = EMPTY_ARRAY; 105 | private int length = 0; 106 | 107 | private QuickNumberArray(Iterable iterable) { 108 | for (Number number : iterable) { 109 | if (length == array.length) { 110 | int increment = length >> 1; 111 | array = Arrays.copyOf(array, length + (increment < MIN_CAPACITY_INCREMENT ? MIN_CAPACITY_INCREMENT : increment)); 112 | } 113 | array[length++] = number; 114 | } 115 | } 116 | 117 | public byte[] toBytes() { 118 | byte[] primitives = new byte[length]; 119 | for (int i = 0; i < length; i++) 120 | primitives[i] = array[i].byteValue(); 121 | return primitives; 122 | } 123 | 124 | public double[] toDoubles() { 125 | double[] primitives = new double[length]; 126 | for (int i = 0; i < length; i++) 127 | primitives[i] = array[i].doubleValue(); 128 | return primitives; 129 | } 130 | 131 | public float[] toFloats() { 132 | float[] primitives = new float[length]; 133 | for (int i = 0; i < length; i++) 134 | primitives[i] = array[i].floatValue(); 135 | return primitives; 136 | } 137 | 138 | public int[] toInts() { 139 | int[] primitives = new int[length]; 140 | for (int i = 0; i < length; i++) 141 | primitives[i] = array[i].intValue(); 142 | return primitives; 143 | } 144 | 145 | public long[] toLongs() { 146 | long[] primitives = new long[length]; 147 | for (int i = 0; i < length; i++) 148 | primitives[i] = array[i].longValue(); 149 | return primitives; 150 | } 151 | 152 | public short[] toShorts() { 153 | short[] primitives = new short[length]; 154 | for (int i = 0; i < length; i++) 155 | primitives[i] = array[i].shortValue(); 156 | return primitives; 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/collectors/ToJoinedString.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import android.text.TextUtils; 4 | 5 | import solid.functions.Func1; 6 | 7 | /** 8 | * This class is a syntax enhancement around {@link TextUtils#join(CharSequence, Iterable)} method 9 | * to chain it with {@link solid.stream.Stream} streams. 10 | */ 11 | public class ToJoinedString { 12 | 13 | private static Func1, String> TO_JOINED_STRING = toJoinedString(""); 14 | 15 | /** 16 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 17 | * to convert an iterable stream of {@link String} type into a joined string. 18 | * 19 | * @return a method that converts an iterable stream of {@link String} type into a joined string. 20 | */ 21 | public static Func1, String> toJoinedString() { 22 | return TO_JOINED_STRING; 23 | } 24 | 25 | /** 26 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 27 | * to convert an iterable stream of {@link String} type into a joined string. 28 | * 29 | * @param delimiter a delimiter 30 | * @return a method that converts an iterable stream of {@link String} type into a joined string. 31 | */ 32 | public static Func1, String> toJoinedString(final String delimiter) { 33 | return new Func1, String>() { 34 | @Override 35 | public String call(Iterable iterable) { 36 | StringBuilder builder = new StringBuilder(); 37 | boolean first = true; 38 | for (String string : iterable) { 39 | if (first) 40 | first = false; 41 | else 42 | builder.append(delimiter); 43 | builder.append(string); 44 | } 45 | return builder.toString(); 46 | } 47 | }; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/collectors/ToList.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import java.util.List; 4 | 5 | import solid.functions.Func1; 6 | 7 | import static solid.collectors.ToArrayList.toArrayList; 8 | 9 | public class ToList { 10 | 11 | /** 12 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 13 | * to convert a stream into a {@link List}. 14 | * 15 | * @param a type of {@link List} items. 16 | * @return a method that converts an iterable into {@link List}. 17 | */ 18 | public static Func1, List> toList() { 19 | return (Func1) toArrayList(); 20 | } 21 | 22 | /** 23 | * Returns a method that can be used with {@link solid.stream.Stream#collect(Func1)} 24 | * to convert a stream into a {@link List}. 25 | *

26 | * Use this method instead of {@link #toList()} for better performance on 27 | * streams that can have more than 12 items. 28 | * 29 | * @param a type of {@link List} items. 30 | * @param initialCapacity initial capacity of the list. 31 | * @return a method that converts an iterable into {@link List}. 32 | */ 33 | public static Func1, List> toList(int initialCapacity) { 34 | return (Func1) toArrayList(initialCapacity); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/functions/Action0.java: -------------------------------------------------------------------------------- 1 | package solid.functions; 2 | 3 | public interface Action0 { 4 | void call(); 5 | } 6 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/functions/Action1.java: -------------------------------------------------------------------------------- 1 | package solid.functions; 2 | 3 | public interface Action1 { 4 | void call(T1 value); 5 | } 6 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/functions/Action2.java: -------------------------------------------------------------------------------- 1 | package solid.functions; 2 | 3 | public interface Action2 { 4 | void call(T1 value1, T2 value2); 5 | } 6 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/functions/Func0.java: -------------------------------------------------------------------------------- 1 | package solid.functions; 2 | 3 | public interface Func0 { 4 | R call(); 5 | } 6 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/functions/Func1.java: -------------------------------------------------------------------------------- 1 | package solid.functions; 2 | 3 | public interface Func1 { 4 | R call(T1 value); 5 | } 6 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/functions/Func2.java: -------------------------------------------------------------------------------- 1 | package solid.functions; 2 | 3 | public interface Func2 { 4 | R call(T1 value1, T2 value2); 5 | } 6 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/optional/Optional.java: -------------------------------------------------------------------------------- 1 | package solid.optional; 2 | 3 | import solid.functions.Action1; 4 | import solid.functions.Func0; 5 | import solid.functions.Func1; 6 | 7 | /** 8 | * Optional is a wrapper around a value that can be empty (null). 9 | * It provides utility methods to handle different cases. 10 | */ 11 | public class Optional { 12 | 13 | private static final Optional EMPTY = new Optional<>(null); 14 | 15 | private final T value; 16 | 17 | private Optional(T value) { 18 | this.value = value; 19 | } 20 | 21 | /** 22 | * Returns an empty optional. 23 | */ 24 | public static Optional empty() { 25 | return (Optional) EMPTY; 26 | } 27 | 28 | /** 29 | * Returns an optional for a given value 30 | */ 31 | public static Optional of(T value) { 32 | return value == null ? (Optional) EMPTY : new Optional<>(value); 33 | } 34 | 35 | /** 36 | * Returns the optional value. Thrown {@link NullPointerException} if the value does not exist. 37 | */ 38 | public T get() { 39 | if (value == null) 40 | throw new NullPointerException(); 41 | return value; 42 | } 43 | 44 | /** 45 | * Returns true if the optional value does exist. 46 | */ 47 | public boolean isPresent() { 48 | return value != null; 49 | } 50 | 51 | /** 52 | * Calls a given action if the optional value does exist. 53 | */ 54 | public void ifPresent(Action1 action) { 55 | if (value != null) 56 | action.call(value); 57 | } 58 | 59 | /** 60 | * Returns the current value or default value if optional does not exist. 61 | */ 62 | public T or(T default1) { 63 | return value != null ? value : default1; 64 | } 65 | 66 | /** 67 | * Returns value of uses a given factory if the value does not exist. 68 | */ 69 | public T or(Func0 func1) { 70 | return value != null ? value : func1.call(); 71 | } 72 | 73 | /** 74 | * Returns the value without null checking it. 75 | */ 76 | public T orNull() { 77 | return value; 78 | } 79 | 80 | /** 81 | * Transforms the value if exists, returns empty Optional otherwise. 82 | */ 83 | public Optional map(Func1 func1) { 84 | return value == null ? Optional.empty() : Optional.of(func1.call(value)); 85 | } 86 | 87 | @Override 88 | public boolean equals(Object o) { 89 | if (this == o) return true; 90 | if (o == null || getClass() != o.getClass()) return false; 91 | 92 | Optional optional = (Optional) o; 93 | 94 | return !(value != null ? !value.equals(optional.value) : optional.value != null); 95 | } 96 | 97 | @Override 98 | public int hashCode() { 99 | return value != null ? value.hashCode() : 0; 100 | } 101 | 102 | @Override 103 | public String toString() { 104 | return "Optional{" + 105 | "value=" + value + 106 | '}'; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/stream/FixedSizeStream.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import java.util.Iterator; 4 | 5 | import solid.functions.Func1; 6 | 7 | class FixedSizeStream extends Stream { 8 | 9 | private final int length; 10 | private final Func1 get; 11 | 12 | public FixedSizeStream(int length, Func1 get) { 13 | this.length = length; 14 | this.get = get; 15 | } 16 | 17 | @Override 18 | public Iterator iterator() { 19 | return new ReadOnlyIterator() { 20 | 21 | int index; 22 | 23 | @Override 24 | public boolean hasNext() { 25 | return index < length; 26 | } 27 | 28 | @Override 29 | public T next() { 30 | return get.call(index++); 31 | } 32 | }; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/stream/Primitives.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import solid.functions.Func1; 4 | 5 | public class Primitives { 6 | 7 | /** 8 | * Creates a new stream of {@link Integer} type that contains all items of a given array. 9 | * 10 | * @param integers an array to get items from. 11 | * @return a new stream of {@link Integer} type that contains all items of a given array. 12 | */ 13 | public static Stream box(final int[] integers) { 14 | return new FixedSizeStream<>(integers.length, new Func1() { 15 | @Override 16 | public Integer call(Integer index) { 17 | return integers[index]; 18 | } 19 | }); 20 | } 21 | 22 | /** 23 | * Creates a new stream of {@link Long} type that contains all items of a given array. 24 | * 25 | * @param longs an array to get items from. 26 | * @return a new stream of {@link Long} type that contains all items of a given array. 27 | */ 28 | public static Stream box(final long[] longs) { 29 | return new FixedSizeStream<>(longs.length, new Func1() { 30 | @Override 31 | public Long call(Integer index) { 32 | return longs[index]; 33 | } 34 | }); 35 | } 36 | 37 | /** 38 | * Creates a new stream of {@link Float} type that contains all items of a given array. 39 | * 40 | * @param floats an array to get items from. 41 | * @return a new stream of {@link Float} type that contains all items of a given array. 42 | */ 43 | public static Stream box(final float[] floats) { 44 | return new FixedSizeStream<>(floats.length, new Func1() { 45 | @Override 46 | public Float call(Integer index) { 47 | return floats[index]; 48 | } 49 | }); 50 | } 51 | 52 | /** 53 | * Creates a new stream of {@link Byte} type that contains all items of a given array. 54 | * 55 | * @param bytes an array to get items from. 56 | * @return a new stream of {@link Byte} type that contains all items of a given array. 57 | */ 58 | public static Stream box(final byte[] bytes) { 59 | return new FixedSizeStream<>(bytes.length, new Func1() { 60 | @Override 61 | public Byte call(Integer index) { 62 | return bytes[index]; 63 | } 64 | }); 65 | } 66 | 67 | /** 68 | * Creates a new stream of {@link Double} type that contains all items of a given array. 69 | * 70 | * @param doubles an array to get items from. 71 | * @return a new stream of {@link Double} type that contains all items of a given array. 72 | */ 73 | public static Stream box(final double[] doubles) { 74 | return new FixedSizeStream<>(doubles.length, new Func1() { 75 | @Override 76 | public Double call(Integer index) { 77 | return doubles[index]; 78 | } 79 | }); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/stream/Range.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import java.util.Iterator; 4 | 5 | public class Range { 6 | 7 | /** 8 | * Creates a stream that contains a given number of integers starting from a given number. 9 | * 10 | * @param from a staring value 11 | * @param to an ending value, exclusive 12 | * @param step the value to add to for the next item 13 | * @return a stream that contains a given number of integers starting from a given number. 14 | */ 15 | public static Stream range(final int from, final int to, final int step) { 16 | return new Stream() { 17 | @Override 18 | public Iterator iterator() { 19 | return new ReadOnlyIterator() { 20 | 21 | int value = from; 22 | 23 | @Override 24 | public boolean hasNext() { 25 | return value < to; 26 | } 27 | 28 | @Override 29 | public Integer next() { 30 | final int v = value; 31 | value += step; 32 | return v; 33 | } 34 | }; 35 | } 36 | }; 37 | } 38 | 39 | /** 40 | * {@link #range(int, int, int)} with 1 as the step parameter. 41 | */ 42 | public static Stream range(final int from, final int to) { 43 | return range(from, to, 1); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/stream/ReadOnlyIterator.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import java.util.Iterator; 4 | 5 | abstract class ReadOnlyIterator implements Iterator { 6 | @Override 7 | public void remove() { 8 | throw new UnsupportedOperationException(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /streams/src/main/java/solid/stream/Stream.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Comparator; 6 | import java.util.HashMap; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | import solid.collections.Grouped; 12 | import solid.collections.Indexed; 13 | import solid.collectors.ToArrayList; 14 | import solid.functions.Action1; 15 | import solid.functions.Func1; 16 | import solid.functions.Func2; 17 | import solid.optional.Optional; 18 | 19 | /** 20 | * This is a base stream class for implementation of iterable streams. 21 | * It provides shortcuts for calling operators in a chaining manner. 22 | * 23 | * @param the type of object returned by the iterator. 24 | */ 25 | public abstract class Stream implements Iterable { 26 | 27 | /** 28 | * Converts a non-primitive array into a {@link Stream}. 29 | * 30 | * @param array array to convert. 31 | * @param a type of array items. 32 | * @return a {@link Stream} that represents source array's elements. 33 | */ 34 | public static Stream stream(final T[] array) { 35 | return new FixedSizeStream<>(array.length, new Func1() { 36 | @Override 37 | public T call(Integer index) { 38 | return array[index]; 39 | } 40 | }); 41 | } 42 | 43 | /** 44 | * Converts a source {@link Iterable} into a {@link Stream}. 45 | * 46 | * @param source a source {@link Iterable} to convert. 47 | * @param a type of stream items 48 | * @return a {@link Stream} that represents source {@link Iterable} elements 49 | */ 50 | public static Stream stream(final Iterable source) { 51 | return new Stream() { 52 | @Override 53 | public Iterator iterator() { 54 | return source.iterator(); 55 | } 56 | }; 57 | } 58 | 59 | /** 60 | * Returns a stream with just one given element. 61 | * 62 | * @param value the element value. 63 | * @param the type of the stream. 64 | * @return a stream with just one given element. 65 | */ 66 | public static Stream of(final T value) { 67 | return new Stream() { 68 | @Override 69 | public Iterator iterator() { 70 | return new ReadOnlyIterator() { 71 | 72 | boolean has = true; 73 | 74 | @Override 75 | public boolean hasNext() { 76 | return has; 77 | } 78 | 79 | @Override 80 | public T next() { 81 | has = false; 82 | return value; 83 | } 84 | }; 85 | } 86 | }; 87 | } 88 | 89 | /** 90 | * Returns a stream of given values. 91 | * 92 | * @param values stream values. 93 | * @param the type of the stream. 94 | * @return a stream of given values. 95 | */ 96 | public static Stream of(T... values) { 97 | return stream(values); 98 | } 99 | 100 | /** 101 | * Returns an empty stream. 102 | * 103 | * @param the type of the stream. 104 | * @return an empty stream. 105 | */ 106 | public static Stream of() { 107 | return EMPTY; 108 | } 109 | 110 | /** 111 | * Converts the current stream into any value with a given method. 112 | * 113 | * @param collector a method that should be used to return value. 114 | * @param a type of value to return. 115 | * @return a value that has been returned by the given collecting method. 116 | */ 117 | public R collect(Func1, R> collector) { 118 | return collector.call(this); 119 | } 120 | 121 | /** 122 | * Returns a value that has been received by applying an accumulating function to each item of the current stream. 123 | * An initial value should be provided. 124 | * 125 | * @param a type of the returning and initial values. 126 | * @param accumulator a function to apply to each stream item. 127 | * @return a value that has been received by applying an accumulating function to each item of the current stream. 128 | */ 129 | public R reduce(R initial, Func2 accumulator) { 130 | R value = initial; 131 | for (T anIt : this) 132 | value = accumulator.call(value, anIt); 133 | return value; 134 | } 135 | 136 | /** 137 | * Returns a value that has been received by applying an accumulating function to each item of the current stream. 138 | * An initial value is taken from the first value. 139 | * 140 | * If the stream is empty an {@link UnsupportedOperationException} will be thrown. 141 | * 142 | * @param accumulator a function to apply to each (except the first one) stream item. 143 | * @return a value that has been received by applying an accumulating function to each item of the current stream. 144 | */ 145 | public Optional reduce(Func2 accumulator) { 146 | Iterator iterator = iterator(); 147 | if (!iterator.hasNext()) 148 | return Optional.empty(); 149 | 150 | T result = iterator.next(); 151 | while (iterator.hasNext()) 152 | result = accumulator.call(result, iterator.next()); 153 | return Optional.of(result); 154 | } 155 | 156 | /** 157 | * Convert an iterable stream into one first item of the stream. 158 | * 159 | * @return the first item of the stream. 160 | */ 161 | public Optional first() { 162 | Iterator iterator = iterator(); 163 | return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.empty(); 164 | } 165 | 166 | /** 167 | * Convert an iterable stream into one last item of the stream. 168 | * 169 | * @return the last item of the stream. 170 | */ 171 | public Optional last() { 172 | Iterator iterator = iterator(); 173 | T value = null; 174 | while (iterator.hasNext()) 175 | value = iterator.next(); 176 | return Optional.of(value); 177 | } 178 | 179 | /** 180 | * Returns a new stream that is created by a given factory. 181 | * The factory accepts the current stream as an argument. 182 | * 183 | * @param factory a method that produces the new stream. 184 | * @param a type of items new stream returns. 185 | * @return a constructed stream. 186 | */ 187 | public Stream compose(Func1, Stream> factory) { 188 | return factory.call(this); 189 | } 190 | 191 | /** 192 | * Returns a new stream that contains items that has been returned by a given function for each item in the current stream. 193 | * 194 | * @param func a function that takes an item of the current stream and returns a corresponding value for the new stream. 195 | * @param a type of items new stream returns. 196 | * @return a new stream that contains items that has been returned by a given function for each item in the current stream. 197 | */ 198 | public Stream map(final Func1 func) { 199 | return new Stream() { 200 | @Override 201 | public Iterator iterator() { 202 | return new ReadOnlyIterator() { 203 | 204 | Iterator iterator = Stream.this.iterator(); 205 | 206 | @Override 207 | public boolean hasNext() { 208 | return iterator.hasNext(); 209 | } 210 | 211 | @Override 212 | public R next() { 213 | return func.call(iterator.next()); 214 | } 215 | }; 216 | } 217 | }; 218 | } 219 | 220 | /** 221 | * Returns a new stream that contains items that has been returned by a given function for each item in the current stream. 222 | * The difference from {@link #map(Func1)} is that a given function can return more than one item for 223 | * each item of the current list. 224 | * 225 | * @param func a function that takes an item of the current stream and returns a stream of values for the new stream. 226 | * @param a type of items new stream returns. 227 | * @return a new stream that contains items that has been returned by a given function for each item in the current stream. 228 | */ 229 | public Stream flatMap(final Func1> func) { 230 | return new Stream() { 231 | @Override 232 | public Iterator iterator() { 233 | return new ReadOnlyIterator() { 234 | 235 | Iterator iterator = Stream.this.iterator(); 236 | Iterator next; 237 | 238 | @Override 239 | public boolean hasNext() { 240 | while ((next == null || !next.hasNext()) && iterator.hasNext()) { 241 | next = func.call(iterator.next()).iterator(); 242 | } 243 | 244 | return next != null && next.hasNext(); 245 | } 246 | 247 | @Override 248 | public R next() { 249 | return next.next(); 250 | } 251 | }; 252 | } 253 | }; 254 | } 255 | 256 | /** 257 | * Returns a new stream that contains all items of the current stream for which a given function returned {@link Boolean#TRUE}. 258 | * 259 | * @param func a function to call for each item. 260 | * @return a new stream that contains all items of the current stream for which a given function returned {@link Boolean#TRUE}. 261 | */ 262 | public Stream filter(final Func1 func) { 263 | return new Stream() { 264 | @Override 265 | public Iterator iterator() { 266 | return new ReadOnlyIterator() { 267 | 268 | Iterator iterator = Stream.this.iterator(); 269 | T next; 270 | boolean hasNext; 271 | 272 | private void process() { 273 | while (!hasNext && iterator.hasNext()) { 274 | final T n = iterator.next(); 275 | if (func.call(n)) { 276 | next = n; 277 | hasNext = true; 278 | } 279 | } 280 | } 281 | 282 | @Override 283 | public boolean hasNext() { 284 | process(); 285 | return hasNext; 286 | } 287 | 288 | @Override 289 | public T next() { 290 | process(); 291 | hasNext = false; 292 | return next; 293 | } 294 | }; 295 | } 296 | }; 297 | } 298 | 299 | /** 300 | * Returns a new stream that contains all items of the current stream with addition of a given item. 301 | * 302 | * @param value a value to add. 303 | * @return a new stream that contains all items of the current stream with addition of a given item. 304 | */ 305 | public Stream merge(final T value) { 306 | return new Stream() { 307 | @Override 308 | public Iterator iterator() { 309 | return new ReadOnlyIterator() { 310 | 311 | Iterator iterator = Stream.this.iterator(); 312 | boolean completed; 313 | 314 | @Override 315 | public boolean hasNext() { 316 | return iterator.hasNext() || !completed; 317 | } 318 | 319 | @Override 320 | public T next() { 321 | if (iterator.hasNext()) 322 | return iterator.next(); 323 | completed = true; 324 | return value; 325 | } 326 | }; 327 | } 328 | }; 329 | } 330 | 331 | /** 332 | * Returns a new stream that contains all items of the current stream except of a given item. 333 | * 334 | * @param value a value to filter out. 335 | * @return a new stream that contains all items of the current stream except of a given item. 336 | */ 337 | public Stream separate(final T value) { 338 | return filter(new Func1() { 339 | @Override 340 | public Boolean call(T it) { 341 | return ((it == null) ? (value != null) : !it.equals(value)); 342 | } 343 | }); 344 | } 345 | 346 | /** 347 | * Adds items from another stream to the end of the current stream. 348 | * 349 | * @param with an {@link Iterable} that should be used to emit items after items in the current stream ran out. 350 | * @return a new stream that contains items from both streams. 351 | */ 352 | public Stream merge(final Iterable with) { 353 | return new Stream() { 354 | @Override 355 | public Iterator iterator() { 356 | return new ReadOnlyIterator() { 357 | 358 | Iterator iterator = Stream.this.iterator(); 359 | Iterator withIterator = with.iterator(); 360 | 361 | @Override 362 | public boolean hasNext() { 363 | return iterator.hasNext() || withIterator.hasNext(); 364 | } 365 | 366 | @Override 367 | public T next() { 368 | return iterator.hasNext() ? iterator.next() : withIterator.next(); 369 | } 370 | }; 371 | } 372 | }; 373 | } 374 | 375 | /** 376 | * Returns a new stream that contains items that has been received by sequentially combining items of the streams into pairs 377 | * and then applying given function to each pair of items. 378 | * 379 | * @param with a {@link Stream} to zip current stream with. 380 | * @param func a function that takes an item of the current stream and an item of another stream 381 | * and returns a corresponding value for the new stream. 382 | * @param a type of a stream to zip current stream with. 383 | * @param a type of items new stream returns. 384 | * @return a new stream that contains items that has been received by sequentially combining items of the streams into pairs 385 | * and then applying given function to each pair of items. 386 | */ 387 | public Stream zipWith(final Iterable with, final Func2 func) { 388 | return new Stream() { 389 | @Override 390 | public Iterator iterator() { 391 | return new ReadOnlyIterator() { 392 | 393 | Iterator iterator = Stream.this.iterator(); 394 | Iterator withIterator = with.iterator(); 395 | 396 | @Override 397 | public boolean hasNext() { 398 | return iterator.hasNext() && withIterator.hasNext(); 399 | } 400 | 401 | @Override 402 | public R next() { 403 | return func.call(iterator.next(), withIterator.next()); 404 | } 405 | }; 406 | } 407 | }; 408 | } 409 | 410 | /** 411 | * Returns a stream that includes only that items of the current stream that do not 412 | * exist in a given stream. 413 | * 414 | * @param from a stream of values that should be separated from the current stream. 415 | * @return a stream that includes only that items of the current stream that do not 416 | * exist in a given stream. 417 | */ 418 | public Stream separate(Iterable from) { 419 | final ArrayList list = ToArrayList.toArrayList().call(from); 420 | return filter(new Func1() { 421 | @Override 422 | public Boolean call(T it) {return !list.contains(it);} 423 | }); 424 | } 425 | 426 | /** 427 | * Creates a new stream that contains only the first given amount of items of the current stream. 428 | * 429 | * @param count a number of items to take. 430 | * @return a new stream that contains only the first given amount of items of the current stream. 431 | */ 432 | public Stream take(final int count) { 433 | return new Stream() { 434 | @Override 435 | public Iterator iterator() { 436 | return new ReadOnlyIterator() { 437 | 438 | Iterator iterator = Stream.this.iterator(); 439 | int left = count; 440 | 441 | @Override 442 | public boolean hasNext() { 443 | return left > 0 && iterator.hasNext(); 444 | } 445 | 446 | @Override 447 | public T next() { 448 | left--; 449 | return iterator.next(); 450 | } 451 | }; 452 | } 453 | }; 454 | } 455 | 456 | /** 457 | * Creates a new stream that contains elements of the current stream with a given number of them skipped from the beginning. 458 | * 459 | * @param count a number items to skip. 460 | * @return a new stream that contains elements of the current stream with a given number of them skipped from the beginning. 461 | */ 462 | public Stream skip(final int count) { 463 | return new Stream() { 464 | @Override 465 | public Iterator iterator() { 466 | Iterator iterator = Stream.this.iterator(); 467 | for (int skip = count; skip > 0 && iterator.hasNext(); skip--) 468 | iterator.next(); 469 | return iterator; 470 | } 471 | }; 472 | } 473 | 474 | /** 475 | * Returns a new stream that filters out duplicate items off the current stream. 476 | *

477 | * This operator keeps a list of all items that has been passed to 478 | * compare it against next items. 479 | * 480 | * @return a new stream that filters out duplicate items off the current stream. 481 | */ 482 | public Stream distinct() { 483 | final ArrayList passed = new ArrayList<>(); 484 | return filter(new Func1() { 485 | @Override 486 | public Boolean call(T value) { 487 | if (passed.contains(value)) 488 | return false; 489 | passed.add(value); 490 | return true; 491 | } 492 | }); 493 | } 494 | 495 | /** 496 | * Returns a new stream that contains all items of the current stream in sorted order. 497 | * The operator creates a list of all items internally. 498 | * 499 | * @param comparator a comparator to apply. 500 | * @return a new stream that contains all items of the current stream in sorted order. 501 | */ 502 | public Stream sort(final Comparator comparator) { 503 | return new Stream() { 504 | @Override 505 | public Iterator iterator() { 506 | final ArrayList array = ToArrayList.toArrayList().call(Stream.this); 507 | Collections.sort(array, comparator); 508 | return array.iterator(); 509 | } 510 | }; 511 | } 512 | 513 | /** 514 | * Returns a new stream that contains all items of the current stream in reverse order. 515 | * The operator creates a list of all items internally. 516 | * 517 | * @return a new stream that emits all items of the current stream in reverse order. 518 | */ 519 | public Stream reverse() { 520 | return new Stream() { 521 | @Override 522 | public Iterator iterator() { 523 | final ArrayList array = ToArrayList.toArrayList().call(Stream.this); 524 | Collections.reverse(array); 525 | return array.iterator(); 526 | } 527 | }; 528 | } 529 | 530 | /** 531 | * Returns a stream that contains all values of the original stream that has been casted to a given class type. 532 | * 533 | * @param c a class to cast into 534 | * @param a type of the class 535 | * @return a stream that contains all values of the original stream that has been casted to a given class type. 536 | */ 537 | public Stream cast(final Class c) { 538 | return map(new Func1() { 539 | @Override 540 | public R call(T obj) {return c.cast(obj);} 541 | }); 542 | } 543 | 544 | /** 545 | * Returns true if all of stream items satisfy a given condition. 546 | * 547 | * @param predicate a condition to test. 548 | * @return true if all of stream items satisfy a given condition. 549 | */ 550 | public boolean every(Func1 predicate) { 551 | for (T item : this) { 552 | if (!predicate.call(item)) 553 | return false; 554 | } 555 | return true; 556 | } 557 | 558 | /** 559 | * Returns true if any of stream items satisfy a given condition. 560 | * 561 | * @param predicate a condition to test. 562 | * @return true if any of stream items satisfy a given condition. 563 | */ 564 | public boolean any(Func1 predicate) { 565 | for (T item : this) { 566 | if (predicate.call(item)) 567 | return true; 568 | } 569 | return false; 570 | } 571 | 572 | /** 573 | * Returns a new stream of {@link Grouped} that is composed from keys and values that has been 574 | * extracted from each source stream item. 575 | * 576 | * @param groupSelector a function that extracts a key from a given item. 577 | * @param valueSelector a function that extracts a value from a given item. 578 | * @param a type of key value. 579 | * @return a new stream of {@link Grouped} that is grouped by a key extracted from each source stream item. 580 | */ 581 | public Stream> groupBy(final Func1 groupSelector, final Func1 valueSelector) { 582 | return new Stream>() { 583 | @Override 584 | public Iterator> iterator() { 585 | List keys = new ArrayList<>(); 586 | final Map> map = new HashMap<>(); 587 | for (T item : Stream.this) { 588 | K key = groupSelector.call(item); 589 | ArrayList list = map.get(key); 590 | if (list == null) { 591 | keys.add(key); 592 | map.put(key, list = new ArrayList<>()); 593 | } 594 | list.add(valueSelector.call(item)); 595 | } 596 | return stream(keys) 597 | .map(new Func1>() { 598 | @Override 599 | public Grouped call(K key) { 600 | return new Grouped<>(key, stream(map.get(key))); 601 | } 602 | }) 603 | .iterator(); 604 | } 605 | }; 606 | } 607 | 608 | /** 609 | * Returns a new stream of {@link Grouped} that is composed from keys that has been 610 | * extracted from each source stream item. 611 | * 612 | * @param groupSelector a function that extracts a key from a given item. 613 | * @param a type of key value. 614 | * @return a new stream of {@link Grouped} that is grouped by a key extracted from each source stream item. 615 | */ 616 | public Stream> groupBy(final Func1 groupSelector) { 617 | return groupBy(groupSelector, new Func1() { 618 | @Override 619 | public T call(T value) { 620 | return value; 621 | } 622 | }); 623 | } 624 | 625 | /** 626 | * Returns a new stream of {@link Indexed} that where each item's index is equal to its sequence number. 627 | * 628 | * @return a new stream of {@link Indexed} that where each item's index is equal to its sequence number. 629 | */ 630 | public Stream> index() { 631 | return map(new Func1>() { 632 | 633 | int i; 634 | 635 | @Override 636 | public Indexed call(T value) { 637 | return new Indexed<>(i++, value); 638 | } 639 | }); 640 | } 641 | 642 | /** 643 | * Executes an action for each item in the stream. 644 | * 645 | * @param action an action to execute for each item in the stream. 646 | */ 647 | public void forEach(Action1 action) { 648 | for (T value : this) 649 | action.call(value); 650 | } 651 | 652 | /** 653 | * Executes an action for each item in the stream. 654 | * 655 | * @param action an action to execute for each item in the stream. 656 | */ 657 | public Stream onNext(final Action1 action) { 658 | return new Stream() { 659 | @Override 660 | public Iterator iterator() { 661 | return new ReadOnlyIterator() { 662 | 663 | Iterator iterator = Stream.this.iterator(); 664 | 665 | @Override 666 | public boolean hasNext() { 667 | return iterator.hasNext(); 668 | } 669 | 670 | @Override 671 | public T next() { 672 | final T next = iterator.next(); 673 | action.call(next); 674 | return next; 675 | } 676 | }; 677 | } 678 | }; 679 | } 680 | 681 | private static final ReadOnlyIterator EMPTY_ITERATOR = new ReadOnlyIterator() { 682 | @Override 683 | public boolean hasNext() { 684 | return false; 685 | } 686 | 687 | @Override 688 | public Object next() { 689 | throw new UnsupportedOperationException(); 690 | } 691 | }; 692 | 693 | private static final Stream EMPTY = new Stream() { 694 | @Override 695 | public Iterator iterator() { 696 | return EMPTY_ITERATOR; 697 | } 698 | }; 699 | } 700 | -------------------------------------------------------------------------------- /streams/src/test/java/solid/collectors/ToArrayTest.java: -------------------------------------------------------------------------------- 1 | package solid.collectors; 2 | 3 | import org.junit.Test; 4 | 5 | import solid.stream.Stream; 6 | 7 | import static org.junit.Assert.assertArrayEquals; 8 | import static solid.collectors.ToArray.toArray; 9 | 10 | public class ToArrayTest { 11 | 12 | @Test 13 | public void testToArray() throws Exception { 14 | assertArrayEquals(new Integer[]{1, 2, 3}, Stream.of(1, 2, 3).collect(toArray(Integer.class))); 15 | assertArrayEquals(new Integer[]{null}, Stream.of((Integer) null).collect(toArray(Integer.class))); 16 | assertArrayEquals(new Integer[]{}, Stream.of().collect(toArray(Integer.class))); 17 | } 18 | } -------------------------------------------------------------------------------- /streams/src/test/java/solid/converters/ToArrayListTest.java: -------------------------------------------------------------------------------- 1 | package solid.converters; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | 8 | import solid.collectors.ToArrayList; 9 | 10 | import static test_utils.AssertIterableEquals.assertIterableEquals; 11 | 12 | public class ToArrayListTest { 13 | @Test 14 | public void testToArrayList() throws Exception { 15 | assertIterableEquals(Arrays.asList(1, 2, 3), ToArrayList.toArrayList().call(Arrays.asList(1, 2, 3))); 16 | assertIterableEquals(Collections.emptyList(), ToArrayList.toArrayList().call(Collections.emptyList())); 17 | assertIterableEquals(Arrays.asList(1, 2, 3), ToArrayList.toArrayList(10).call(Arrays.asList(1, 2, 3))); 18 | assertIterableEquals(Collections.emptyList(), ToArrayList.toArrayList(10).call(Collections.emptyList())); 19 | } 20 | } -------------------------------------------------------------------------------- /streams/src/test/java/solid/converters/ToArraysTest.java: -------------------------------------------------------------------------------- 1 | package solid.converters; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | 8 | import solid.collectors.ToArrays; 9 | 10 | import static org.junit.Assert.assertArrayEquals; 11 | import static solid.collectors.ToArrays.toBytes; 12 | import static solid.stream.Stream.of; 13 | 14 | public class ToArraysTest { 15 | 16 | @Test 17 | public void toBytes1() throws Exception { 18 | of((byte) 1, (byte) 2, (byte) 3).collect(ToArrays.toBytes()); 19 | assertArrayEquals(new byte[]{1, 2, 3}, toBytes().call(Arrays.asList((byte) 1, (byte) 2, (byte) 3))); 20 | assertArrayEquals(new byte[]{}, toBytes().call(Collections.emptyList())); 21 | } 22 | 23 | @Test 24 | public void toDoubles() throws Exception { 25 | of(1., 2., 3.).collect(ToArrays.toDoubles()); 26 | assertArrayEquals(new double[]{1., 2., 3.}, ToArrays.toDoubles().call(Arrays.asList((double) 1, (double) 2, (double) 3)), 0); 27 | assertArrayEquals(new double[]{}, ToArrays.toDoubles().call(Collections.emptyList()), 0); 28 | } 29 | 30 | @Test 31 | public void toFloats() throws Exception { 32 | of(1f, 2f, 3f).collect(ToArrays.toFloats()); 33 | assertArrayEquals(new float[]{1, 2, 3}, ToArrays.toFloats().call(Arrays.asList(1f, 2f, 3f)), 0); 34 | assertArrayEquals(new float[]{}, ToArrays.toFloats().call(Collections.emptyList()), 0); 35 | } 36 | 37 | @Test 38 | public void toInts() throws Exception { 39 | of(1, 2, 3).collect(ToArrays.toInts()); 40 | assertArrayEquals(new int[]{1, 2, 3}, ToArrays.toInts().call(Arrays.asList(1, 2, 3))); 41 | assertArrayEquals(new int[]{}, ToArrays.toInts().call(Collections.emptyList())); 42 | } 43 | 44 | @Test 45 | public void toLongs() throws Exception { 46 | of(1l, 2l, 3l).collect(ToArrays.toLongs()); 47 | assertArrayEquals(new long[]{1, 2, 3}, ToArrays.toLongs().call(Arrays.asList(1L, 2L, 3L))); 48 | assertArrayEquals(new long[]{}, ToArrays.toLongs().call(Collections.emptyList())); 49 | } 50 | 51 | @Test 52 | public void toShorts() throws Exception { 53 | of((short) 1, (short) 2, (short) 3).collect(ToArrays.toShorts()); 54 | assertArrayEquals(new short[]{1, 2, 3}, ToArrays.toShorts().call(Arrays.asList((short) 1, (short) 2, (short) 3))); 55 | assertArrayEquals(new short[]{}, ToArrays.toShorts().call(Collections.emptyList())); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /streams/src/test/java/solid/converters/ToJoinedStringTest.java: -------------------------------------------------------------------------------- 1 | package solid.converters; 2 | 3 | import org.junit.Test; 4 | 5 | import solid.stream.Stream; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | import static solid.collectors.ToJoinedString.toJoinedString; 9 | import static solid.stream.Stream.of; 10 | 11 | public class ToJoinedStringTest { 12 | 13 | @Test 14 | public void testToJoinedString() throws Exception { 15 | assertEquals("1,2,3", of("1", "2", "3").collect(toJoinedString(","))); 16 | assertEquals("123", of("1", "2", "3").collect(toJoinedString())); 17 | assertEquals("", Stream.of().collect(toJoinedString())); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /streams/src/test/java/solid/converters/ToListTest.java: -------------------------------------------------------------------------------- 1 | package solid.converters; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | 8 | import solid.collectors.ToList; 9 | 10 | import static test_utils.AssertIterableEquals.assertIterableEquals; 11 | 12 | public class ToListTest { 13 | @Test 14 | public void testToList() throws Exception { 15 | assertIterableEquals(Arrays.asList(1, 2, 3), ToList.toList().call(Arrays.asList(1, 2, 3))); 16 | assertIterableEquals(Collections.emptyList(), ToList.toList().call(Collections.emptyList())); 17 | assertIterableEquals(Arrays.asList(1, 2, 3), ToList.toList(10).call(Arrays.asList(1, 2, 3))); 18 | assertIterableEquals(Collections.emptyList(), ToList.toList(10).call(Collections.emptyList())); 19 | } 20 | } -------------------------------------------------------------------------------- /streams/src/test/java/solid/optional/OptionalTest.java: -------------------------------------------------------------------------------- 1 | package solid.optional; 2 | 3 | import org.junit.Test; 4 | 5 | import solid.functions.Action1; 6 | import solid.functions.Func0; 7 | import solid.functions.Func1; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertNull; 12 | import static org.junit.Assert.assertTrue; 13 | import static org.mockito.Matchers.eq; 14 | import static org.mockito.Mockito.mock; 15 | import static org.mockito.Mockito.times; 16 | import static org.mockito.Mockito.verify; 17 | import static org.mockito.Mockito.verifyNoMoreInteractions; 18 | 19 | public class OptionalTest { 20 | 21 | @Test 22 | public void testNull() throws Exception { 23 | Optional o = Optional.of(null); 24 | 25 | assertFalse(o.isPresent()); 26 | 27 | Action1 mockAction = mock(Action1.class); 28 | o.ifPresent(mockAction); 29 | verifyNoMoreInteractions(mockAction); 30 | 31 | assertEquals(1, o.or(1)); 32 | assertEquals(1, o.or(new Func0() { 33 | @Override 34 | public Object call() {return 1;} 35 | })); 36 | assertNull(o.orNull()); 37 | assertNull(o.map(null).orNull()); 38 | 39 | assertTrue(o.equals(Optional.empty())); 40 | 41 | assertEquals(o.hashCode(), Optional.empty().hashCode()); 42 | } 43 | 44 | @Test(expected = NullPointerException.class) 45 | public void testNullNPE() throws Exception { 46 | Optional.of(null).get(); 47 | } 48 | 49 | @Test 50 | public void testValue() throws Exception { 51 | Optional o = Optional.of(1); 52 | 53 | assertTrue(o.isPresent()); 54 | 55 | Action1 mockAction = mock(Action1.class); 56 | o.ifPresent(mockAction); 57 | verify(mockAction, times(1)).call(eq(1)); 58 | 59 | assertEquals((Integer) 1, o.or(2)); 60 | assertEquals((Integer) 1, o.or(new Func0() { 61 | @Override 62 | public Integer call() { 63 | return 2; 64 | } 65 | })); 66 | assertEquals((Integer) 1, o.orNull()); 67 | assertEquals("1", o.map(new Func1() { 68 | @Override 69 | public String call(Integer value) { 70 | return value.toString(); 71 | } 72 | }).get()); 73 | 74 | assertTrue(Optional.of(1).equals(o)); 75 | 76 | assertEquals(o.hashCode(), Optional.of(1).hashCode()); 77 | 78 | assertEquals((Integer) 1, o.get()); 79 | } 80 | } -------------------------------------------------------------------------------- /streams/src/test/java/solid/stream/FixedSizeStreamTest.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Iterator; 6 | 7 | import solid.functions.Func1; 8 | 9 | import static java.util.Arrays.asList; 10 | import static java.util.Collections.emptyList; 11 | import static test_utils.AssertIterableEquals.assertIterableEquals; 12 | 13 | public class FixedSizeStreamTest { 14 | 15 | @Test 16 | public void testIterator() throws Exception { 17 | assertIterableEquals(asList("0", "1", "2"), create3()); 18 | assertIterableEquals(emptyList(), new FixedSizeStream<>(0, null)); 19 | } 20 | 21 | @Test(expected = UnsupportedOperationException.class) 22 | public void testReadOnly() throws Exception { 23 | Iterator iterator = create3().iterator(); 24 | iterator.next(); 25 | iterator.remove(); 26 | } 27 | 28 | private FixedSizeStream create3() { 29 | return new FixedSizeStream<>(3, new Func1() { 30 | @Override 31 | public String call(Integer value) { 32 | return value.toString(); 33 | } 34 | }); 35 | } 36 | } -------------------------------------------------------------------------------- /streams/src/test/java/solid/stream/PrimitivesTest.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | 8 | import static test_utils.AssertIterableEquals.assertIterableEquals; 9 | 10 | public class PrimitivesTest { 11 | 12 | @Test 13 | public void boxedIntegers() throws Exception { 14 | assertIterableEquals(Arrays.asList(1, 2, 3), Primitives.box(new int[]{1, 2, 3})); 15 | assertIterableEquals(Collections.emptyList(), Primitives.box(new int[0])); 16 | assertIterableEquals(Primitives.box(new int[]{1, 2, 3}), Primitives.box(new int[]{1, 2, 3})); 17 | } 18 | 19 | @Test 20 | public void boxedLongs() throws Exception { 21 | assertIterableEquals(Arrays.asList(1l, 2l, 3l), Primitives.box(new long[]{1, 2, 3})); 22 | assertIterableEquals(Collections.emptyList(), Primitives.box(new long[0])); 23 | assertIterableEquals(Primitives.box(new long[]{1, 2, 3}), Primitives.box(new long[]{1, 2, 3})); 24 | } 25 | 26 | @Test 27 | public void boxedFloats() throws Exception { 28 | assertIterableEquals(Arrays.asList(1f, 2f, 3f), Primitives.box(new float[]{1, 2, 3})); 29 | assertIterableEquals(Collections.emptyList(), Primitives.box(new float[0])); 30 | assertIterableEquals(Primitives.box(new float[]{1, 2, 3}), Primitives.box(new float[]{1, 2, 3})); 31 | } 32 | 33 | @Test 34 | public void boxedBytes() throws Exception { 35 | assertIterableEquals(Arrays.asList((byte) 1, (byte) 2, (byte) 3), Primitives.box(new byte[]{1, 2, 3})); 36 | assertIterableEquals(Collections.emptyList(), Primitives.box(new byte[0])); 37 | assertIterableEquals(Primitives.box(new byte[]{1, 2, 3}), Primitives.box(new byte[]{1, 2, 3})); 38 | } 39 | 40 | @Test 41 | public void boxedDoubles() throws Exception { 42 | assertIterableEquals(Arrays.asList(1., 2., 3.), Primitives.box(new double[]{1, 2, 3})); 43 | assertIterableEquals(Collections.emptyList(), Primitives.box(new double[0])); 44 | assertIterableEquals(Primitives.box(new double[]{1, 2, 3}), Primitives.box(new double[]{1, 2, 3})); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /streams/src/test/java/solid/stream/RangeTest.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Collections; 6 | 7 | import static java.util.Arrays.asList; 8 | import static java.util.Collections.singletonList; 9 | import static solid.stream.Range.range; 10 | import static test_utils.AssertIterableEquals.assertIterableEquals; 11 | 12 | public class RangeTest { 13 | @Test 14 | public void testRange() throws Exception { 15 | assertIterableEquals(asList(1, 2, 3), range(1, 4)); 16 | assertIterableEquals(asList(1, 3, 5), range(1, 6, 2)); 17 | assertIterableEquals(asList(-3, -2, -1), range(-3, 0)); 18 | assertIterableEquals(Collections.emptyList(), range(1, 1)); 19 | assertIterableEquals(singletonList(1), range(1, 2)); 20 | } 21 | } -------------------------------------------------------------------------------- /streams/src/test/java/solid/stream/ReadOnlyIteratorTest.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertTrue; 6 | 7 | public class ReadOnlyIteratorTest { 8 | @Test(expected = UnsupportedOperationException.class) 9 | public void testRemove() throws Exception { 10 | new ReadOnlyIterator() { 11 | @Override 12 | public boolean hasNext() { 13 | return true; 14 | } 15 | 16 | @Override 17 | public Object next() { 18 | return null; 19 | } 20 | }.remove(); 21 | } 22 | 23 | @Test 24 | public void testIntegration() throws Exception { 25 | assertTrue(Stream.of(1).iterator() instanceof ReadOnlyIterator); 26 | } 27 | } -------------------------------------------------------------------------------- /streams/src/test/java/solid/stream/StreamTest.java: -------------------------------------------------------------------------------- 1 | package solid.stream; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Collections; 8 | import java.util.Comparator; 9 | import java.util.HashMap; 10 | import java.util.Iterator; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.concurrent.atomic.AtomicBoolean; 14 | 15 | import solid.collections.Grouped; 16 | import solid.collections.Indexed; 17 | import solid.functions.Action1; 18 | import solid.functions.Func1; 19 | import solid.functions.Func2; 20 | 21 | import static java.util.Arrays.asList; 22 | import static java.util.Collections.emptyList; 23 | import static java.util.Collections.singletonList; 24 | import static junit.framework.Assert.assertEquals; 25 | import static junit.framework.Assert.assertFalse; 26 | import static junit.framework.Assert.assertTrue; 27 | import static solid.stream.Stream.of; 28 | import static solid.stream.Stream.stream; 29 | import static test_utils.AssertIterableEquals.assertGroupedEquals; 30 | import static test_utils.AssertIterableEquals.assertIterableEquals; 31 | 32 | public class StreamTest { 33 | 34 | @Test 35 | public void testStreamOfArray() throws Exception { 36 | assertIterableEquals(asList(1, 2, 3), stream(asList(1, 2, 3).toArray(new Integer[3]))); 37 | assertIterableEquals(Collections.emptyList(), stream(new Object[]{})); 38 | assertIterableEquals(asList(null, null), stream(new Object[]{null, null})); 39 | } 40 | 41 | @Test 42 | public void testStreamOfIterator() throws Exception { 43 | assertIterableEquals(asList(1, 2, 3), stream(asList(1, 2, 3))); 44 | assertIterableEquals(Collections.emptyList(), stream(Collections.emptyList())); 45 | assertIterableEquals(asList(null, null), stream(asList(null, null))); 46 | } 47 | 48 | @Test 49 | public void testOf() throws Exception { 50 | assertIterableEquals(singletonList(1), of(1)); 51 | assertIterableEquals(asList(null, null), of(null, null)); 52 | assertIterableEquals(asList(1, 2, 3), of(1, 2, 3)); 53 | } 54 | 55 | @Test 56 | public void testOfVararg() throws Exception { 57 | assertIterableEquals(asList(1, null, 2), of(1, null, 2)); 58 | assertIterableEquals(emptyList(), of()); 59 | } 60 | 61 | @Test 62 | public void testEmpty() throws Exception { 63 | assertIterableEquals(emptyList(), Stream.of()); 64 | Iterator iterator = Stream.of().iterator(); 65 | assertFalse(iterator.hasNext()); 66 | } 67 | 68 | @Test(expected = UnsupportedOperationException.class) 69 | public void testEmptyThrows() throws Exception { 70 | Stream.of().iterator().next(); 71 | } 72 | 73 | @Test 74 | public void testLift() throws Exception { 75 | assertIterableEquals(asList(1, 3, 6), stream(asList(1, 2, 3)) 76 | .compose(new Func1, Stream>() { 77 | @Override 78 | public Stream call(final Stream value) { 79 | return new Stream() { 80 | @Override 81 | public Iterator iterator() { 82 | return new ReadOnlyIterator() { 83 | 84 | Iterator source = value.iterator(); 85 | int count; 86 | 87 | @Override 88 | public boolean hasNext() { 89 | return source.hasNext(); 90 | } 91 | 92 | @Override 93 | public Integer next() { 94 | return count += source.next(); 95 | } 96 | }; 97 | } 98 | }; 99 | } 100 | })); 101 | } 102 | 103 | @Test 104 | public void testMap() throws Exception { 105 | assertIterableEquals(asList("1", "2", "3"), of(1, 2, 3).map(new Func1() { 106 | @Override 107 | public String call(Integer integer) {return integer.toString();} 108 | })); 109 | assertIterableEquals(Arrays.asList(null, null), of(null, null).map(new Func1() { 110 | @Override 111 | public Integer call(Object value) {return null;} 112 | })); 113 | assertIterableEquals(emptyList(), of().map(new Func1() { 114 | @Override 115 | public Object call(Object value) {return null;} 116 | })); 117 | } 118 | 119 | @Test 120 | public void testFlatMap() throws Exception { 121 | assertIterableEquals(asList("2", "3", "4", "3", "4", "5", "4", "5", "6"), of(1, 2, 3).flatMap(new Func1>() { 122 | @Override 123 | public Iterable call(Integer value) {return asList("" + (value + 1), "" + (value + 2), "" + (value + 3));} 124 | })); 125 | assertIterableEquals(Arrays.asList(null, null, null, null), of(null, null).flatMap(new Func1>() { 126 | @Override 127 | public Iterable call(Object value) {return Arrays.asList(null, null);} 128 | })); 129 | assertIterableEquals(emptyList(), of().flatMap(new Func1>() { 130 | @Override 131 | public Iterable call(Object value) {return null;} 132 | })); 133 | 134 | HashMap> map = new HashMap>() {{ 135 | put(0, asList("1", "2")); 136 | put(1, Collections.emptyList()); 137 | put(2, Collections.emptyList()); 138 | put(3, Collections.emptyList()); 139 | put(4, asList("3")); 140 | }}; 141 | assertIterableEquals(asList("1", "2", "3"), stream(map.entrySet()).flatMap(new Func1>, Iterable>() { 142 | @Override 143 | public Iterable call(Map.Entry> value) { 144 | return value.getValue(); 145 | } 146 | })); 147 | 148 | HashMap> map2 = new HashMap>() {{ 149 | put(1, Collections.emptyList()); 150 | put(2, Collections.emptyList()); 151 | put(3, Collections.emptyList()); 152 | put(0, asList("1", "2")); 153 | put(4, asList("3")); 154 | }}; 155 | assertIterableEquals(asList("1", "2", "3"), stream(map2.entrySet()).flatMap(new Func1>, Iterable>() { 156 | @Override 157 | public Iterable call(Map.Entry> value) { 158 | return value.getValue(); 159 | } 160 | })); 161 | } 162 | 163 | @Test 164 | public void testFilter() throws Exception { 165 | assertIterableEquals(asList(1, 2, 3), stream(asList(1, 2, 3, 4)).filter(new Func1() { 166 | @Override 167 | public Boolean call(Integer value) {return value != 4;} 168 | })); 169 | List list123 = asList(1, 2, 3); 170 | assertIterableEquals(list123, of(1, 2, 3, 4).filter(new Func1() { 171 | @Override 172 | public Boolean call(Integer value) {return value != 4;} 173 | })); 174 | assertIterableEquals(list123, of(4, 1, 2, 3).filter(new Func1() { 175 | @Override 176 | public Boolean call(Integer value) {return value != 4;} 177 | })); 178 | assertIterableEquals(list123, of(1, 2, 4, 3).filter(new Func1() { 179 | @Override 180 | public Boolean call(Integer value) {return value != 4;} 181 | })); 182 | assertIterableEquals(list123, of(1, 2, 3).filter(new Func1() { 183 | @Override 184 | public Boolean call(Integer value) {return true;} 185 | })); 186 | assertIterableEquals(Collections.emptyList(), of(1, 2, 4, 3).filter(new Func1() { 187 | @Override 188 | public Boolean call(Integer value) {return false;} 189 | })); 190 | assertIterableEquals(Collections.emptyList(), Stream.of().filter(new Func1() { 191 | @Override 192 | public Boolean call(Integer value) {return true;} 193 | })); 194 | assertIterableEquals(Collections.emptyList(), Stream.of(null, null).filter(new Func1() { 195 | @Override 196 | public Boolean call(Integer value) {return false;} 197 | })); 198 | } 199 | 200 | @Test 201 | public void testWith() throws Exception { 202 | assertIterableEquals(asList(1, 2, 3), stream(asList(1, 2)).merge(3)); 203 | assertIterableEquals(asList(1, 2, null), stream(asList(1, 2)).merge((Integer) null)); 204 | } 205 | 206 | @Test 207 | public void testWithout() throws Exception { 208 | assertIterableEquals(asList(1, 2, 3), stream(asList(1, 2, 3, 4)).separate(4)); 209 | assertIterableEquals(asList(1, 2, 3), stream(asList(1, 2, 3, null)).separate((Integer) null)); 210 | } 211 | 212 | @Test 213 | public void testMerge() throws Exception { 214 | assertIterableEquals(asList(1, 2, 3, 4), of(1, 2).merge(of(3, 4))); 215 | assertIterableEquals(asList(1, 2, 3, 4, 5, 6), of(1, 2, 3).merge(of(4, 5, 6))); 216 | assertIterableEquals(asList(1, 2, 3), of(1, 2, 3).merge(Stream.of())); 217 | assertIterableEquals(asList(4, 5, 6), Stream.of().merge(Stream.of(4, 5, 6))); 218 | assertIterableEquals(Collections.emptyList(), of().merge(of())); 219 | assertIterableEquals(asList(null, null, null, null), of(null, null).merge(of(null, null))); 220 | } 221 | 222 | @Test 223 | public void testZipWith() throws Exception { 224 | final Func2 add = new Func2() { 225 | @Override 226 | public Integer call(Integer lhs, Integer rhs) {return lhs + rhs;} 227 | }; 228 | assertIterableEquals(asList(2, 4, 6), of(1, 2, 3).zipWith(of(1, 2, 3), add)); 229 | assertIterableEquals(asList(7, 9), of(1, 2, 3, 4, 5).zipWith(of(6, 7), add)); 230 | assertIterableEquals(asList(7, 9), of(6, 7).zipWith(of(1, 2, 3, 4, 5), add)); 231 | assertIterableEquals(Collections.emptyList(), Stream.of().zipWith(of(1, 2, 3), add)); 232 | } 233 | 234 | @Test 235 | public void testSeparate() throws Exception { 236 | assertIterableEquals(asList(1, 2, 3), stream(asList(0, 1, 4, 5, 6, 2, 3, null)).separate(asList(0, 4, 5, 6, null))); 237 | } 238 | 239 | @Test 240 | public void testTake() throws Exception { 241 | assertIterableEquals(asList(1, 2), of(1, 2, 3).take(2)); 242 | assertIterableEquals(asList(1, 2), of(1, 2).take(10)); 243 | assertIterableEquals(asList(null, null), of(null, null).take(3)); 244 | assertIterableEquals(emptyList(), of().take(10)); 245 | assertIterableEquals(emptyList(), of().take(0)); 246 | } 247 | 248 | @Test 249 | public void testSkip() throws Exception { 250 | assertIterableEquals(asList(3, 4, 5), of(1, 2, 3, 4, 5).skip(2)); 251 | assertIterableEquals(asList(3, 4, 5), of(3, 4, 5).skip(0)); 252 | assertIterableEquals(Collections.emptyList(), of(1, 2, 3, 4, 5).skip(5)); 253 | assertIterableEquals(Collections.emptyList(), of(1, 2, 3).skip(5)); 254 | assertIterableEquals(Collections.emptyList(), of().skip(5)); 255 | assertIterableEquals(asList(null, null), of(null, null, null).skip(1)); 256 | } 257 | 258 | @Test 259 | public void testDistinct() throws Exception { 260 | assertIterableEquals(asList(1, 2, 3), stream(asList(1, 2, 3, 3, 3)).distinct()); 261 | assertIterableEquals(singletonList(null), stream(asList(null, null)).distinct()); 262 | assertIterableEquals(emptyList(), stream(asList()).distinct()); 263 | } 264 | 265 | @Test 266 | public void testSort() throws Exception { 267 | assertIterableEquals(asList(1, 2, 3), stream(asList(3, 2, 1)).sort(new Comparator() { 268 | @Override 269 | public int compare(Integer lhs, Integer rhs) {return lhs < rhs ? -1 : (lhs.equals(rhs) ? 0 : 1);} 270 | })); 271 | assertIterableEquals(asList(1, 2, 3), of(3, 2, 1).sort(new Comparator() { 272 | @Override 273 | public int compare(Integer lhs, Integer rhs) {return lhs < rhs ? -1 : (lhs.equals(rhs) ? 0 : 1);} 274 | })); 275 | assertIterableEquals(asList(null, null), of(null, null).sort(new Comparator() { 276 | @Override 277 | public int compare(Object lhs, Object rhs) {return 0;} 278 | })); 279 | assertIterableEquals(emptyList(), of().sort(new Comparator() { 280 | @Override 281 | public int compare(Object lhs, Object rhs) {return 0;} 282 | })); 283 | } 284 | 285 | @Test 286 | public void testReverse() throws Exception { 287 | assertIterableEquals(asList(1, 2, 3), of(3, 2, 1).reverse()); 288 | assertIterableEquals(asList(null, null), of(null, null).reverse()); 289 | assertIterableEquals(singletonList(1), of(1)); 290 | assertIterableEquals(emptyList(), of().reverse()); 291 | } 292 | 293 | @Test 294 | public void testCollect() throws Exception { 295 | final ArrayList target = new ArrayList<>(); 296 | ArrayList result = stream(asList(1, 2, 3)).collect(new Func1, ArrayList>() { 297 | @Override 298 | public ArrayList call(Iterable value) { 299 | for (Integer v : value) 300 | target.add(v); 301 | return target; 302 | } 303 | }); 304 | assertTrue(target == result); 305 | assertEquals(target, result); 306 | } 307 | 308 | @Test 309 | public void testFold() throws Exception { 310 | assertEquals(null, Stream.of().reduce(null, new Func2() { 311 | @Override 312 | public Object call(Object it, Object that) {return null;} 313 | })); 314 | assertEquals(null, Stream.of(null, null).reduce(null, new Func2() { 315 | @Override 316 | public Object call(Object value1, Object value2) {return null;} 317 | })); 318 | assertEquals((Integer) 10, Stream.of(2, 3, 4).reduce(1, new Func2() { 319 | @Override 320 | public Integer call(Integer value1, Integer value2) {return value1 + value2;} 321 | })); 322 | } 323 | 324 | @Test 325 | public void testReduce() throws Exception { 326 | 327 | assertFalse(Stream.of().reduce(null).isPresent()); 328 | 329 | assertEquals((Integer) 9, Stream.of(9).reduce(null).get()); 330 | assertFalse(null, Stream.of(null, null, null).reduce(new Func2() { 331 | @Override 332 | public Object call(Object value1, Object value2) {return null;} 333 | }).isPresent()); 334 | assertEquals((Integer) 9, Stream.of(2, 3, 4).reduce(new Func2() { 335 | @Override 336 | public Integer call(Integer value1, Integer value2) {return value1 + value2;} 337 | }).get()); 338 | } 339 | 340 | @Test 341 | public void testFirst() throws Exception { 342 | assertEquals((Long) 1L, of(1L).first().get()); 343 | assertEquals((Long) 1L, of(1L, 2L, 3L).first().get()); 344 | assertFalse(of().first().isPresent()); 345 | assertFalse(of(null, 2L, 3L).first().isPresent()); 346 | } 347 | 348 | @Test 349 | public void testLast() throws Exception { 350 | assertEquals(1, (int) of(1).last().get()); 351 | assertEquals(3, (int) of(1, 2, 3).last().get()); 352 | assertFalse(of().last().isPresent()); 353 | assertEquals(3, (int) of(1, null, 3).last().get()); 354 | assertFalse(of(1, 1, null).last().isPresent()); 355 | } 356 | 357 | @Test 358 | public void testCast() throws Exception { 359 | List list = asList(1, 2, 3); 360 | List numbers = asList((Number) 1, 2, 3); 361 | assertIterableEquals(numbers, stream(list).cast(Number.class)); 362 | } 363 | 364 | @Test(expected = ClassCastException.class) 365 | public void testCastException() throws Exception { 366 | List numbers = asList(1, 2, 3); 367 | //noinspection unchecked 368 | assertIterableEquals(numbers, of("1").cast(Integer.class)); 369 | } 370 | 371 | @Test 372 | public void testEvery() { 373 | assertTrue(Stream.of(1, 1, 1).every(new Func1() { 374 | @Override 375 | public Boolean call(Integer it) { 376 | return it == 1; 377 | } 378 | })); 379 | assertFalse(Stream.of(1, 2, 1).every(new Func1() { 380 | @Override 381 | public Boolean call(Integer it) { 382 | return it == 1; 383 | } 384 | })); 385 | assertTrue(Stream.of().every(null)); 386 | } 387 | 388 | @Test 389 | public void testAny() { 390 | assertTrue(Stream.of(2, 7, 1).any(new Func1() { 391 | @Override 392 | public Boolean call(Integer it) { 393 | return it == 1; 394 | } 395 | })); 396 | assertFalse(Stream.of(4, 2, 2).any(new Func1() { 397 | @Override 398 | public Boolean call(Integer it) { 399 | return it == 1; 400 | } 401 | })); 402 | assertFalse(Stream.of().any(null)); 403 | } 404 | 405 | @Test 406 | public void testGroupBy2() { 407 | assertGroupedEquals(of(new Grouped<>(0, of(1, 3)), new Grouped<>(10, of(2, 3))), 408 | of(1, 12, 3, 13) 409 | .groupBy( 410 | new Func1() { 411 | @Override 412 | public Integer call(Integer value) { 413 | return value - value % 10; 414 | } 415 | }, 416 | new Func1() { 417 | @Override 418 | public Integer call(Integer value) { 419 | return value % 10; 420 | } 421 | })); 422 | assertGroupedEquals(Stream.>of(), Stream.of().groupBy(null, null)); 423 | assertGroupedEquals(Stream.of(new Grouped<>(null, of((Object) null))), Stream.of((Object) null).groupBy(new Func1() { 424 | @Override 425 | public Object call(Object value) { 426 | return null; 427 | } 428 | }, new Func1() { 429 | @Override 430 | public Object call(Object value) { 431 | return null; 432 | } 433 | })); 434 | } 435 | 436 | @Test 437 | public void testGroupBy1() throws Exception { 438 | assertGroupedEquals(of(new Grouped<>(0, of(1, 3)), new Grouped<>(10, of(12, 13))), 439 | of(1, 12, 3, 13) 440 | .groupBy(new Func1() { 441 | @Override 442 | public Integer call(Integer value) { 443 | return value - value % 10; 444 | } 445 | })); 446 | } 447 | 448 | @Test 449 | public void testIndex() throws Exception { 450 | assertIterableEquals(of(new Indexed<>(0, 1), new Indexed<>(1, 12), new Indexed<>(2, 3), new Indexed<>(3, 13)), 451 | of(1, 12, 3, 13).index()); 452 | assertIterableEquals(of(new Indexed<>(0, 1), new Indexed(1, null)), 453 | of(1, null).index()); 454 | assertIterableEquals(Stream.>of(), of().index()); 455 | } 456 | 457 | @Test 458 | public void testForEach() throws Exception { 459 | 460 | Stream stream = of(1, 12, 3, 13); 461 | final ArrayList collected = new ArrayList<>(); 462 | stream.forEach(new Action1() { 463 | @Override 464 | public void call(Integer value) { 465 | collected.add(value); 466 | } 467 | }); 468 | assertIterableEquals(stream, collected); 469 | 470 | final AtomicBoolean called = new AtomicBoolean(); 471 | of().forEach(new Action1() { 472 | @Override 473 | public void call(Object value) { 474 | called.set(true); 475 | } 476 | }); 477 | assertFalse(called.get()); 478 | 479 | final ArrayList collected2 = new ArrayList<>(); 480 | Stream stream2 = of(null, 3); 481 | stream2.forEach(new Action1() { 482 | @Override 483 | public void call(Integer value) { 484 | collected2.add(value); 485 | } 486 | }); 487 | assertIterableEquals(stream2, collected2); 488 | } 489 | 490 | @Test 491 | public void testOnNext() throws Exception { 492 | final ArrayList collected = new ArrayList<>(); 493 | of(1, 2, 3) 494 | .filter(new Func1() { 495 | @Override 496 | public Boolean call(Integer value) { 497 | return value > 1; 498 | } 499 | }) 500 | .onNext(new Action1() { 501 | @Override 502 | public void call(Integer value) { 503 | collected.add(value); 504 | } 505 | }) 506 | .filter(new Func1() { 507 | @Override 508 | public Boolean call(Integer value) { 509 | return value < 3; 510 | } 511 | }) 512 | .last(); 513 | assertIterableEquals(of(2, 3), collected); 514 | } 515 | } 516 | -------------------------------------------------------------------------------- /streams/src/test/java/test_utils/AssertIterableEquals.java: -------------------------------------------------------------------------------- 1 | package test_utils; 2 | 3 | import java.util.Iterator; 4 | 5 | import solid.collections.Grouped; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | import static org.junit.Assert.assertFalse; 9 | 10 | public class AssertIterableEquals { 11 | public static void assertIterableEquals(Iterable iterable1, Iterable iterable2) { 12 | Iterator iterator1 = iterable1.iterator(); 13 | Iterator iterator2 = iterable2.iterator(); 14 | while (iterator1.hasNext() && iterator2.hasNext()) 15 | assertEquals(iterator1.next(), iterator2.next()); 16 | assertFalse(iterator1.hasNext()); 17 | assertFalse(iterator2.hasNext()); 18 | } 19 | 20 | public static void assertGroupedEquals(Iterable iterable1, Iterable iterable2) { 21 | Iterator iterator1 = iterable1.iterator(); 22 | Iterator iterator2 = iterable2.iterator(); 23 | while (iterator1.hasNext() && iterator2.hasNext()) { 24 | T next1 = iterator1.next(); 25 | T next2 = iterator2.next(); 26 | assertEquals(next1.group, next2.group); 27 | assertIterableEquals(next1.stream, next2.stream); 28 | } 29 | assertFalse(iterator1.hasNext()); 30 | assertFalse(iterator2.hasNext()); 31 | } 32 | } 33 | --------------------------------------------------------------------------------