├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src ├── main │ └── java │ │ └── com │ │ └── fernandocejas │ │ └── arrow │ │ ├── annotations │ │ ├── Internal.java │ │ ├── Beta.java │ │ ├── Experimental.java │ │ ├── WorkInProgress.java │ │ ├── See.java │ │ ├── Issue.java │ │ └── VisibleForTesting.java │ │ ├── collections │ │ ├── RandomAccessPartition.java │ │ ├── RandomAccessReverseList.java │ │ ├── UnmodifiableIterator.java │ │ ├── Partition.java │ │ ├── CollectPreconditions.java │ │ ├── FilteredCollection.java │ │ ├── MoreArrays.java │ │ ├── ReverseList.java │ │ ├── MoreCollections.java │ │ ├── AbstractIterator.java │ │ ├── Lists.java │ │ ├── Iterators.java │ │ └── Iterables.java │ │ ├── functions │ │ ├── Predicate.java │ │ ├── Function.java │ │ └── Functions.java │ │ ├── optional │ │ ├── Present.java │ │ ├── Absent.java │ │ └── Optional.java │ │ ├── size │ │ └── SizeUnit.java │ │ ├── strings │ │ ├── Charsets.java │ │ ├── Strings.java │ │ └── Joiner.java │ │ ├── checks │ │ └── Preconditions.java │ │ └── objects │ │ └── MoreObjects.java └── test │ └── java │ └── com │ └── fernandocejas │ └── arrow │ └── size │ └── SizeUnitTest.java ├── .gitignore ├── dev.txt ├── gradle.properties ├── gradlew.bat ├── publish.gradle ├── README.md ├── gradlew └── LICENSE /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/arrow/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Feb 06 00:13:47 CET 2016 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.10-all.zip 7 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/annotations/Internal.java: -------------------------------------------------------------------------------- 1 | package com.fernandocejas.arrow.annotations; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | /** 7 | * Denotes that the class, method or field is declared as Internal functionality. 8 | * This can be used in scenarios in which the functionality is replaced with a new one, but it hasn't been deprecated. 9 | */ 10 | @Retention(RetentionPolicy.SOURCE) 11 | public @interface Internal { 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows thumbnail db 2 | Thumbs.db 3 | 4 | # OSX files 5 | .DS_Store 6 | 7 | # Java class files 8 | *.class 9 | 10 | # generated files 11 | bin/ 12 | gen/ 13 | build/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Eclipse project files 19 | .classpath 20 | .project 21 | 22 | # Intellij 23 | .idea 24 | .gradle 25 | .gradletasknamecache 26 | /*/local.properties 27 | /*/out 28 | /*/*/build 29 | build 30 | /*/*/production 31 | *.iml 32 | *.iws 33 | *.ipr 34 | *~ 35 | *.swp 36 | -------------------------------------------------------------------------------- /dev.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------- 2 | New Arrow version (TODO: automate this part) 3 | ---------------------------------------------------------- 4 | 1. Publish through gradle task: 5 | - ./gradlew publishArrow 6 | - Ignore this warning: "Skipping upload for missing file..." 7 | - https://github.com/novoda/bintray-release/issues/51 8 | 9 | 10 | 2. Go to https://bintray.com/android10 and publish the files to both jcenter() and mavenCentral() 11 | 12 | 3. Prepare for the next development version: 13 | - gradle.properties version property 14 | ---------------------------------------------------------- -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | #Project Properties 2 | codename=arrow 3 | artifact=arrow 4 | group=com.fernandocejas 5 | version=1.0.0 6 | description=Lightweight library toolbox for Java and Android Development 7 | website=https://github.com/android10/arrow 8 | issues=https://github.com/android10/arrow/issues 9 | repository=maven 10 | license=Apache-2.0 11 | 12 | #Developer 13 | user=android10 14 | userwebsite=https://github.com/android10 15 | fullname=Fernando Cejas 16 | email=fcejas@gmail.com 17 | organization=Fernando Cejas 18 | organizationUrl=https://www.fernandocejas.com 19 | 20 | #Plugins 21 | bintrayPluginVersion=1.6 22 | 23 | #Dependencies 24 | annotationsVersion=13.0 25 | 26 | #Test dependencies 27 | junitVersion=4.12 28 | assertJVersion=3.2.0 29 | mockitoVersion=1.10.19 30 | 31 | #Gradle Properties 32 | org.gradle.daemon=true 33 | org.gradle.parallel=true 34 | org.gradle.configureondemand=true -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/RandomAccessPartition.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import java.util.List; 19 | import java.util.RandomAccess; 20 | 21 | class RandomAccessPartition extends Partition 22 | implements RandomAccess { 23 | RandomAccessPartition(List list, int size) { 24 | super(list, size); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/RandomAccessReverseList.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import java.util.List; 19 | import java.util.RandomAccess; 20 | 21 | class RandomAccessReverseList extends ReverseList 22 | implements RandomAccess { 23 | RandomAccessReverseList(List forwardList) { 24 | super(forwardList); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/annotations/Beta.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Fernando Cejas Open Source Project 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 | package com.fernandocejas.arrow.annotations; 17 | 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | 21 | /** 22 | * Denotes that the class, method or field is declared as Beta functionality. 23 | */ 24 | @Retention(RetentionPolicy.SOURCE) 25 | public @interface Beta { 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/annotations/Experimental.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Fernando Cejas Open Source Project 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 | package com.fernandocejas.arrow.annotations; 17 | 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | 21 | /** 22 | * Denotes that the class, method or field is declared as Experimental. 23 | */ 24 | @Retention(RetentionPolicy.SOURCE) 25 | public @interface Experimental { 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/annotations/WorkInProgress.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Fernando Cejas Open Source Project 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 | package com.fernandocejas.arrow.annotations; 17 | 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | 21 | /** 22 | * Denotes that the class, method or field is declared as work in progress. 23 | */ 24 | @Retention(RetentionPolicy.SOURCE) 25 | public @interface WorkInProgress { 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/annotations/See.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Fernando Cejas Open Source Project 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 | package com.fernandocejas.arrow.annotations; 17 | 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | 21 | /** 22 | * Denotes that the class, method or field is linked to a link. 23 | * A ref value should be added in order to specify the link url. 24 | */ 25 | @Retention(RetentionPolicy.SOURCE) 26 | public @interface See { 27 | String ref(); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/annotations/Issue.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Fernando Cejas Open Source Project 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 | package com.fernandocejas.arrow.annotations; 17 | 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | 21 | /** 22 | * Denotes that the class, method or field is linked to an issue. 23 | * A ref value can be added in order to specify more information. 24 | */ 25 | @Retention(RetentionPolicy.SOURCE) 26 | public @interface Issue { 27 | String ref(); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/annotations/VisibleForTesting.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Fernando Cejas Open Source Project 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 | package com.fernandocejas.arrow.annotations; 17 | 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | 21 | /** 22 | * Denotes that the class, method or field has its visibility relaxed, so that it is more widely 23 | * visible than otherwise necessary to make code testable. 24 | */ 25 | @Retention(RetentionPolicy.SOURCE) 26 | public @interface VisibleForTesting { 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/UnmodifiableIterator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2008 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import java.util.Iterator; 19 | 20 | /** 21 | * An iterator that does not support {@link #remove}. 22 | * 23 | * @author Jared Levy 24 | * @since 2.0 (imported from Google Collections Library) 25 | * 26 | *

This class contains code derived from Google 27 | * Guava 28 | */ 29 | public abstract class UnmodifiableIterator implements Iterator { 30 | /** 31 | * Constructor for use by subclasses. 32 | */ 33 | protected UnmodifiableIterator() { 34 | } 35 | 36 | /** 37 | * Guaranteed to throw an exception and leave the underlying data unmodified. 38 | * 39 | * @throws UnsupportedOperationException always 40 | * @deprecated Unsupported operation. 41 | */ 42 | @Override 43 | public final void remove() { 44 | throw new UnsupportedOperationException(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/Partition.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import java.util.AbstractList; 19 | import java.util.List; 20 | 21 | import static com.fernandocejas.arrow.checks.Preconditions.checkElementIndex; 22 | 23 | class Partition extends AbstractList> { 24 | final List list; 25 | final int size; 26 | 27 | Partition(List list, int size) { 28 | this.list = list; 29 | this.size = size; 30 | } 31 | 32 | @Override 33 | public List get(int index) { 34 | checkElementIndex(index, size()); 35 | int start = index * size; 36 | int end = Math.min(start + size, list.size()); 37 | return list.subList(start, end); 38 | } 39 | 40 | @Override 41 | public int size() { 42 | int div = list.size() / size; 43 | int rem = list.size() % size; 44 | if (rem == 0) { 45 | return div; 46 | } else { 47 | return div + 1; 48 | } 49 | } 50 | 51 | @Override 52 | public boolean isEmpty() { 53 | return list.isEmpty(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/CollectPreconditions.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import static com.fernandocejas.arrow.checks.Preconditions.checkState; 19 | 20 | /** 21 | * Precondition checks useful in collection implementations. 22 | */ 23 | public final class CollectPreconditions { 24 | 25 | public static void checkIndexNonnegative(int value) { 26 | if (value < 0) { 27 | throw new IndexOutOfBoundsException("value (" + value 28 | + ") must not be negative"); 29 | } 30 | } 31 | 32 | public static int checkNonnegative(int value, String name) { 33 | if (value < 0) { 34 | throw new IllegalArgumentException(name + " cannot be negative but was: " + value); 35 | } 36 | return value; 37 | } 38 | 39 | /** 40 | * Precondition tester for {@code Iterator.remove()} that throws an exception with a consistent 41 | * error message. 42 | */ 43 | static void checkRemove(boolean canRemove) { 44 | checkState(canRemove, "no calls to next() since the last call to remove()"); 45 | } 46 | 47 | public static Object[] checkElementsNotNull(Object... array) { 48 | return checkElementsNotNull(array, array.length); 49 | } 50 | 51 | public static Object[] checkElementsNotNull(Object[] array, int length) { 52 | for (int i = 0; i < length; i++) { 53 | checkElementNotNull(array[i], i); 54 | } 55 | return array; 56 | } 57 | 58 | // We do this instead of Preconditions.checkNotNull to save boxing and array 59 | // creation cost. 60 | public static Object checkElementNotNull(Object element, int index) { 61 | if (element == null) { 62 | throw new NullPointerException("at index " + index); 63 | } 64 | return element; 65 | } 66 | 67 | private CollectPreconditions() { 68 | // no instances 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/functions/Predicate.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.functions; 17 | 18 | import org.jetbrains.annotations.Nullable; 19 | 20 | /** 21 | * Determines a true or false value for a given input. 22 | * 23 | *

The {@link Predicates} class provides common predicates and related utilities. 24 | * 25 | *

See the Guava User Guide article on the use of {@code 27 | * Predicate}. 28 | * 29 | * @author Kevin Bourrillion 30 | * @since 2.0 (imported from Google Collections Library) 31 | */ 32 | public interface Predicate { 33 | /** 34 | * Returns the result of applying this predicate to {@code input}. This method is generally 35 | * expected, but not absolutely required, to have the following properties: 36 | * 37 | *

    38 | *
  • Its execution does not cause any observable side effects. 39 | *
  • The computation is consistent with equals. 40 | * Objects.equal}{@code (a, b)} implies that {@code predicate.apply(a) == 41 | * predicate.apply(b))}. 42 | *
43 | * 44 | * @throws NullPointerException if {@code input} is null and this predicate does not accept null 45 | * arguments 46 | */ 47 | boolean apply(@Nullable T input); 48 | 49 | /** 50 | * Indicates whether another object is equal to this predicate. 51 | * 52 | *

Most implementations will have no reason to override the behavior of {@link Object#equals}. 53 | * However, an implementation may also choose to return {@code true} whenever {@code object} is a 54 | * {@link Predicate} that it considers interchangeable with this one. "Interchangeable" 55 | * typically means that {@code this.apply(t) == that.apply(t)} for all {@code t} of type 56 | * {@code T}). Note that a {@code false} result from this method does not imply that the 57 | * predicates are known not to be interchangeable. 58 | */ 59 | @Override boolean equals(@Nullable Object object); 60 | } 61 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/functions/Function.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.functions; 17 | 18 | import org.jetbrains.annotations.Nullable; 19 | 20 | /** 21 | * Determines an output value based on an input value. 22 | * 23 | *

The {@link Functions} class provides common functions and related utilites. 24 | * 25 | *

See the Guava User Guide article on the use of {@code 27 | * Function}. 28 | * 29 | * @author Kevin Bourrillion 30 | * @since 2.0 (imported from Google Collections Library) 31 | * 32 | *

This class contains code derived from Google 33 | * Guava 34 | */ 35 | public interface Function { 36 | /** 37 | * Returns the result of applying this function to {@code input}. This method is generally 38 | * expected, but not absolutely required, to have the following properties: 39 | * 40 | *

    41 | *
  • Its execution does not cause any observable side effects. 42 | *
  • The computation is consistent with equals. 43 | * Objects.equal}{@code (a, b)} implies that {@code Objects.equal(function.apply(a), 44 | * function.apply(b))}. 45 | *
46 | * 47 | * @throws NullPointerException if {@code input} is null 48 | */ 49 | @Nullable T apply(F input); 50 | 51 | /** 52 | * Indicates whether another object is equal to this function. 53 | * 54 | *

Most implementations will have no reason to override the behavior of {@link Object#equals}. 55 | * However, an implementation may also choose to return {@code true} whenever {@code object} is a 56 | * {@link Function} that it considers interchangeable with this one. "Interchangeable" 57 | * typically means that {@code Objects.equal(this.apply(f), that.apply(f))} is true for 58 | * all 59 | * {@code f} of type {@code F}. Note that a {@code false} result from this method does not imply 60 | * that the functions are known not to be interchangeable. 61 | */ 62 | @Override boolean equals(@Nullable Object object); 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/optional/Present.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2011 The Guava Authors 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 | package com.fernandocejas.arrow.optional; 17 | 18 | import com.fernandocejas.arrow.functions.Function; 19 | import java.util.Collections; 20 | import java.util.Set; 21 | import org.jetbrains.annotations.Nullable; 22 | 23 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 24 | 25 | /** 26 | * Implementation of an {@link Optional} containing a reference. 27 | * 28 | *

This class contains code derived from Google 29 | * Guava 30 | */ 31 | final class Present extends Optional { 32 | private static final long serialVersionUID = 0; 33 | 34 | private final T reference; 35 | 36 | Present(T reference) { 37 | this.reference = reference; 38 | } 39 | 40 | @Override 41 | public boolean isPresent() { 42 | return true; 43 | } 44 | 45 | @Override 46 | public T get() { 47 | return reference; 48 | } 49 | 50 | @Override 51 | public T or(T defaultValue) { 52 | checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)"); 53 | return reference; 54 | } 55 | 56 | @Override 57 | public Optional or(Optional secondChoice) { 58 | checkNotNull(secondChoice); 59 | return this; 60 | } 61 | 62 | @Override 63 | public T orNull() { 64 | return reference; 65 | } 66 | 67 | @Override 68 | public Set asSet() { 69 | return Collections.singleton(reference); 70 | } 71 | 72 | @Override 73 | public Optional transform(Function function) { 74 | return new Present<>(checkNotNull(function.apply(reference), 75 | "the Function passed to Optional.transform() must not return null.")); 76 | } 77 | 78 | @Override 79 | public boolean equals(@Nullable Object object) { 80 | if (object instanceof Present) { 81 | Present other = (Present) object; 82 | return reference.equals(other.reference); 83 | } 84 | return false; 85 | } 86 | 87 | @Override 88 | public int hashCode() { 89 | return 0x598df91c + reference.hashCode(); 90 | } 91 | 92 | @Override 93 | public String toString() { 94 | return "Optional.of(" + reference + ")"; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/size/SizeUnit.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Fernando Cejas Open Source Project 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 | package com.fernandocejas.arrow.size; 17 | 18 | import com.fernandocejas.arrow.annotations.WorkInProgress; 19 | 20 | @WorkInProgress 21 | enum SizeUnit { 22 | 23 | BYTES { 24 | public double toBytes(double d) { return 0; } 25 | public double toKilobytes(long d) { return 0; } 26 | public double toMegabytes(long d) { return 0; } 27 | public double toGigabytes(long d) { return 0; } 28 | public double toTerabytes(long d) { return 0; } 29 | }, 30 | 31 | KILOBYTES { 32 | public double toBytes(double d) { return 0; } 33 | public double toKilobytes(long d) { return 0; } 34 | public double toMegabytes(long d) { return 0; } 35 | public double toGigabytes(long d) { return 0; } 36 | public double toTerabytes(long d) { return 0; } 37 | }, 38 | 39 | MEGABYTES { 40 | public double toBytes(double d) { return 0; } 41 | public double toKilobytes(long d) { return 0; } 42 | public double toMegabytes(long d) { return 0; } 43 | public double toGigabytes(long d) { return 0; } 44 | public double toTerabytes(long d) { return 0; } 45 | }, 46 | 47 | GIGABYTES { 48 | public double toBytes(double d) { return 0; } 49 | public double toKilobytes(long d) { return 0; } 50 | public double toMegabytes(long d) { return 0; } 51 | public double toGigabytes(long d) { return 0; } 52 | public double toTerabytes(long d) { return 0; } 53 | }, 54 | 55 | TERABYTES { 56 | public double toBytes(double d) { return 0; } 57 | public double toKilobytes(long d) { return 0; } 58 | public double toMegabytes(long d) { return 0; } 59 | public double toGigabytes(long d) { return 0; } 60 | public double toTerabytes(long d) { return 0; } 61 | }; 62 | 63 | public double toBytes(double size) { 64 | throw new AbstractMethodError(); 65 | } 66 | 67 | public double toKilobytes(long size) { 68 | throw new AbstractMethodError(); 69 | } 70 | 71 | public double toMegabytes(long size) { 72 | throw new AbstractMethodError(); 73 | } 74 | 75 | public double toGigabytes(long size) { 76 | throw new AbstractMethodError(); 77 | } 78 | 79 | public double toTerabytes(long size) { 80 | throw new AbstractMethodError(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/optional/Absent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2011 The Guava Authors 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 | package com.fernandocejas.arrow.optional; 17 | 18 | import com.fernandocejas.arrow.functions.Function; 19 | import java.util.Collections; 20 | import java.util.Set; 21 | import org.jetbrains.annotations.Nullable; 22 | 23 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 24 | 25 | /** 26 | * Implementation of an {@link Optional} not containing a reference. 27 | * 28 | *

This class contains code derived from Google 29 | * Guava 30 | */ 31 | final class Absent extends Optional { 32 | private static final long serialVersionUID = 0; 33 | 34 | static final Absent INSTANCE = new Absent<>(); 35 | 36 | @SuppressWarnings("unchecked") // implementation is "fully variant" 37 | static Optional withType() { 38 | return (Optional) INSTANCE; 39 | } 40 | 41 | private Absent() { 42 | } 43 | 44 | @Override 45 | public boolean isPresent() { 46 | return false; 47 | } 48 | 49 | @Override 50 | public T get() { 51 | throw new IllegalStateException("Optional.get() cannot be called on an absent value"); 52 | } 53 | 54 | @Override 55 | public T or(T defaultValue) { 56 | return checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)"); 57 | } 58 | 59 | @SuppressWarnings("unchecked") // safe covariant cast 60 | @Override 61 | public Optional or(Optional secondChoice) { 62 | return (Optional) checkNotNull(secondChoice); 63 | } 64 | 65 | @Override 66 | @Nullable 67 | public T orNull() { 68 | return null; 69 | } 70 | 71 | @Override 72 | public Set asSet() { 73 | return Collections.emptySet(); 74 | } 75 | 76 | @Override 77 | public Optional transform(Function function) { 78 | checkNotNull(function); 79 | return absent(); 80 | } 81 | 82 | @Override 83 | public boolean equals(@Nullable Object object) { 84 | return object == this; 85 | } 86 | 87 | @Override 88 | public int hashCode() { 89 | return 0x598df91c; 90 | } 91 | 92 | @Override 93 | public String toString() { 94 | return "Optional.absent()"; 95 | } 96 | 97 | private Object readResolve() { 98 | return INSTANCE; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/strings/Charsets.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.strings; 17 | 18 | import java.nio.charset.Charset; 19 | 20 | /** 21 | * Contains constant definitions for the six standard {@link Charset} instances, which are 22 | * guaranteed to be supported by all Java platform implementations. 23 | * 24 | *

Assuming you're free to choose, note that {@link #UTF_8} is widely preferred. 25 | * 26 | *

See the Guava User Guide article on 28 | * {@code Charsets}. 29 | * 30 | * @author Mike Bostock 31 | * @since 1.0 32 | */ 33 | public final class Charsets { 34 | 35 | /** 36 | * US-ASCII: seven-bit ASCII, the Basic Latin block of the Unicode character set (ISO646-US). 37 | * 38 | *

Note for Java 7 and later: this constant should be treated as deprecated; use 39 | * {@link java.nio.charset.StandardCharsets#US_ASCII} instead. 40 | */ 41 | public static final Charset US_ASCII = Charset.forName("US-ASCII"); 42 | 43 | /** 44 | * ISO-8859-1: ISO Latin Alphabet Number 1 (ISO-LATIN-1). 45 | * 46 | *

Note for Java 7 and later: this constant should be treated as deprecated; use 47 | * {@link java.nio.charset.StandardCharsets#ISO_8859_1} instead. 48 | */ 49 | public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); 50 | 51 | /** 52 | * UTF-8: eight-bit UCS Transformation Format. 53 | * 54 | *

Note for Java 7 and later: this constant should be treated as deprecated; use 55 | * {@link java.nio.charset.StandardCharsets#UTF_8} instead. 56 | */ 57 | public static final Charset UTF_8 = Charset.forName("UTF-8"); 58 | 59 | /** 60 | * UTF-16: sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order 61 | * mark. 62 | * 63 | *

Note for Java 7 and later: this constant should be treated as deprecated; use 64 | * {@link java.nio.charset.StandardCharsets#UTF_16} instead. 65 | */ 66 | public static final Charset UTF_16 = Charset.forName("UTF-16"); 67 | 68 | /* 69 | * Please do not add new Charset references to this class, unless those character encodings are 70 | * part of the set required to be supported by all Java platform implementations! Any Charsets 71 | * initialized here may cause unexpected delays when this class is loaded. See the Charset 72 | * Javadocs for the list of built-in character encodings. 73 | */ 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/com/fernandocejas/arrow/size/SizeUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.fernandocejas.arrow.size; 2 | 3 | import com.fernandocejas.arrow.annotations.See; 4 | import com.fernandocejas.arrow.annotations.WorkInProgress; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.runners.MockitoJUnitRunner; 9 | 10 | import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; 11 | 12 | @WorkInProgress 13 | @See(ref = "https://www.google.de/search?q=convert+kilobytes+to+mb") 14 | @Ignore 15 | @RunWith(MockitoJUnitRunner.class) 16 | public class SizeUnitTest { 17 | 18 | @Test 19 | public void shouldConvertKilobytesToBytes() { 20 | double resultOne = SizeUnit.KILOBYTES.toBytes(123543); 21 | assertThat(resultOne).isEqualTo(123543000); 22 | 23 | double resultTwo = SizeUnit.KILOBYTES.toBytes(888); 24 | assertThat(resultTwo).isEqualTo(888000); 25 | 26 | double resultThree = SizeUnit.KILOBYTES.toBytes(987611); 27 | assertThat(resultThree).isEqualTo(987611000); 28 | 29 | double resultFour = SizeUnit.KILOBYTES.toBytes(1432); 30 | assertThat(resultFour).isEqualTo(1432000); 31 | } 32 | 33 | @Test 34 | public void shouldConvertKilobytesToKilobytes() { 35 | double resultOne = SizeUnit.KILOBYTES.toKilobytes(9); 36 | assertThat(resultOne).isEqualTo(9); 37 | 38 | double resultTwo = SizeUnit.KILOBYTES.toKilobytes(495855); 39 | assertThat(resultTwo).isEqualTo(495855); 40 | } 41 | 42 | @Test 43 | public void shouldConvertKilobytesToMegabytes() { 44 | double resultOne = SizeUnit.KILOBYTES.toMegabytes(111); 45 | assertThat(resultOne).isEqualTo(0.111); 46 | 47 | double resultTwo = SizeUnit.KILOBYTES.toMegabytes(2324234); 48 | assertThat(resultTwo).isEqualTo(2324.234); 49 | 50 | double resultThree = SizeUnit.KILOBYTES.toMegabytes(320492384); 51 | assertThat(resultThree).isEqualTo(320492.384); 52 | 53 | double resultFour = SizeUnit.KILOBYTES.toMegabytes(999999999); 54 | assertThat(resultFour).isEqualTo(999999.999); 55 | } 56 | 57 | @Test 58 | public void shouldConvertKilobytesToGigabytes() { 59 | double resultOne = SizeUnit.KILOBYTES.toGigabytes(2342342); 60 | assertThat(resultOne).isEqualTo(2.342342); 61 | 62 | double resultTwo = SizeUnit.KILOBYTES.toGigabytes(34995); 63 | assertThat(resultTwo).isEqualTo(0.034995); 64 | 65 | double resultThree = SizeUnit.KILOBYTES.toGigabytes(4534); 66 | assertThat(resultThree).isEqualTo(0.004534); 67 | 68 | double resultFour = SizeUnit.KILOBYTES.toGigabytes(1000); 69 | assertThat(resultFour).isEqualTo(0.001); 70 | } 71 | 72 | @Test 73 | public void shouldConvertKilobytesToTerabytes() { 74 | double resultOne = SizeUnit.KILOBYTES.toTerabytes(233234); 75 | assertThat(resultOne).isEqualTo(0.000233234); 76 | 77 | double resultTwo = SizeUnit.KILOBYTES.toTerabytes(888888); 78 | assertThat(resultTwo).isEqualTo(0.000888888); 79 | 80 | double resultThree = SizeUnit.KILOBYTES.toTerabytes(89795867); 81 | assertThat(resultThree).isEqualTo(0.089795867); 82 | 83 | double resultFour = SizeUnit.KILOBYTES.toTerabytes(32402234); 84 | assertThat(resultFour).isEqualTo(0.032402234); 85 | } 86 | } -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/strings/Strings.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2008 The Guava Authors 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 | package com.fernandocejas.arrow.strings; 17 | 18 | import java.math.BigInteger; 19 | import java.util.Locale; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | /** 23 | * General utility functions pertaining to {@link String}s. 24 | * 25 | *

This class contains code derived from Google 26 | * Guava 27 | */ 28 | public final class Strings { 29 | 30 | public static final String EMPTY = ""; 31 | 32 | /** 33 | * Returns the given string if it is non-null; the empty string otherwise. 34 | * 35 | * @param string the string to test and possibly return 36 | * @return {@code string} itself if it is non-null; {@code ""} if it is null 37 | */ 38 | public static String nullToEmpty(@Nullable CharSequence string) { 39 | return string == null ? EMPTY : string.toString(); 40 | } 41 | 42 | /** 43 | * Returns {@code true} if the given string is null or is the empty string. 44 | * 45 | * @param string a string reference to check 46 | * @return {@code true} if the string is null or is the empty string 47 | */ 48 | public static boolean isNullOrEmpty(@Nullable CharSequence string) { 49 | return string == null || string.length() == 0; 50 | } 51 | 52 | /** 53 | * @return true if the string only contains white space or if {@link #isNullOrEmpty(CharSequence)} 54 | * would return true; false otherwise. 55 | */ 56 | public static boolean isBlank(@Nullable CharSequence string) { 57 | return isNullOrEmpty(nullToEmpty(string).trim()); 58 | } 59 | 60 | /** 61 | * The converse of {@link #isBlank(CharSequence)} 62 | */ 63 | public static boolean isNotBlank(@Nullable CharSequence string) { 64 | return !isBlank(string); 65 | } 66 | 67 | public static String safeToString(@Nullable Object object) { 68 | return object == null ? EMPTY : object.toString(); 69 | } 70 | 71 | /** 72 | * Converts the given bytes to a hexidecimal strings including leading zeros. 73 | * If you do not need leading zeros, you can use Java's toString(16) instead. 74 | */ 75 | public static String toHexString(byte[] bytes) { 76 | return String.format(Locale.US, "%0" + (bytes.length << 1) + "x", new BigInteger(1, bytes)); 77 | } 78 | 79 | /** 80 | * Returns a joiner which automatically places {@code separator} between consecutive elements. 81 | */ 82 | public static Joiner joinOn(String separator) { 83 | return new Joiner(separator); 84 | } 85 | 86 | /** 87 | * Returns a joiner which automatically places {@code separator} between consecutive elements. 88 | */ 89 | public static Joiner joinOn(char separator) { 90 | return new Joiner(String.valueOf(separator)); 91 | } 92 | 93 | private Strings() { 94 | // no instances 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /publish.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'maven' 3 | apply plugin: 'maven-publish' 4 | 5 | apply plugin: 'com.jfrog.bintray' 6 | 7 | def buildDirectory = "$buildDir/libs" 8 | def pomFilePath = "$buildDirectory/$project.artifact-$project.version" + ".pom" 9 | 10 | if (JavaVersion.current().isJava8Compatible()) { 11 | allprojects { 12 | tasks.withType(Javadoc) { 13 | options.addStringOption('Xdoclint:none', '-quiet') 14 | } 15 | } 16 | } 17 | 18 | //https://maven.apache.org/guides/mini/guide-central-repository-upload.html 19 | //http://central.sonatype.org/pages/requirements.html#a-complete-example-pom 20 | //https://medium.com/@vyarus/the-hard-way-to-maven-central-c9e16d163acc#.t0evkiaet 21 | def pomConfig = { 22 | licenses { 23 | license { 24 | name "The Apache Software License, Version 2.0" 25 | url "http://www.apache.org/licenses/LICENSE-2.0.txt" 26 | distribution "repo" 27 | } 28 | } 29 | developers { 30 | developer { 31 | name "$project.fullname" 32 | email "$project.email" 33 | organization "$project.organization" 34 | organizationUrl "$project.organizationUrl" 35 | } 36 | } 37 | scm { 38 | connection "$project.website" 39 | developerConnection "$project.userwebsite" 40 | url "$project.website" 41 | } 42 | } 43 | 44 | publishing { 45 | publications { 46 | mavenJava(MavenPublication) { 47 | groupId "$project.group" 48 | artifactId "$project.artifact" 49 | version "$project.version" 50 | from components.java 51 | artifact sourcesJar 52 | artifact javadocJar 53 | pom.withXml { 54 | def pomNode = asNode() 55 | //Clean up useless stuff in order to organize it 56 | pomNode.remove(pomNode.get("packaging")) 57 | //Add the information 58 | pomNode.appendNode('packaging', 'jar') 59 | pomNode.appendNode('name', "$project.name") 60 | pomNode.appendNode('description', "$project.description") 61 | pomNode.appendNode('url', "$project.website") 62 | pomNode.children().last() + pomConfig 63 | } 64 | artifact "$pomFilePath" 65 | } 66 | } 67 | } 68 | 69 | bintray { 70 | user = System.getenv('BINTRAY_USERNAME') 71 | key = System.getenv('BINTRAY_KEY') 72 | publications = ['mavenJava'] 73 | pkg { 74 | repo = "$project.repository" 75 | name = "$project.codename" 76 | desc = "$project.description" 77 | websiteUrl = "$project.website" 78 | issueTrackerUrl = "$project.issues" 79 | licenses = ["$project.license"] 80 | vcsUrl = "$project.website" 81 | labels = ['android', 'java', 'arrow'] 82 | //noinspection GroovyAssignabilityCheck 83 | version { 84 | name = "$project.version" 85 | desc = "$project.description" 86 | released = new Date() 87 | vcsTag = "$project.website" 88 | mavenCentralSync { 89 | sync = true 90 | user = System.getenv('OSS_USERNAME') 91 | password = System.getenv('OSS_KEY') 92 | close = '1' 93 | } 94 | } 95 | } 96 | } 97 | 98 | task sourcesJar(type: Jar, dependsOn: classes) { 99 | classifier 'sources' 100 | from sourceSets.main.allSource 101 | } 102 | 103 | task javadocJar(type: Jar, dependsOn: javadoc) { 104 | classifier 'javadoc' 105 | //noinspection GrUnresolvedAccess 106 | from javadoc.destinationDir 107 | } 108 | 109 | artifacts { 110 | archives sourcesJar 111 | archives javadocJar 112 | } 113 | 114 | task installToLocalRepo(dependsOn: ['publishMavenJavaPublicationToMavenLocal']) {} 115 | model { 116 | tasks.generatePomFileForMavenJavaPublication { 117 | pomDir = file("$pomFilePath") 118 | destination = file("$pomFilePath") 119 | } 120 | } -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/FilteredCollection.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import com.fernandocejas.arrow.functions.Predicate; 19 | import com.fernandocejas.arrow.functions.Predicates; 20 | import java.util.AbstractCollection; 21 | import java.util.Collection; 22 | import java.util.Iterator; 23 | import org.jetbrains.annotations.Nullable; 24 | 25 | import static com.fernandocejas.arrow.checks.Preconditions.checkArgument; 26 | 27 | class FilteredCollection extends AbstractCollection { 28 | final Collection unfiltered; 29 | final Predicate predicate; 30 | 31 | FilteredCollection(Collection unfiltered, 32 | Predicate predicate) { 33 | this.unfiltered = unfiltered; 34 | this.predicate = predicate; 35 | } 36 | 37 | FilteredCollection createCombined(Predicate newPredicate) { 38 | return new FilteredCollection<>(unfiltered, 39 | Predicates.and(predicate, newPredicate)); 40 | // . above needed to compile in JDK 5 41 | } 42 | 43 | @Override 44 | public boolean add(E element) { 45 | checkArgument(predicate.apply(element)); 46 | return unfiltered.add(element); 47 | } 48 | 49 | @Override 50 | public boolean addAll(Collection collection) { 51 | for (E element : collection) { 52 | checkArgument(predicate.apply(element)); 53 | } 54 | return unfiltered.addAll(collection); 55 | } 56 | 57 | @Override 58 | public void clear() { 59 | Iterables.removeIf(unfiltered, predicate); 60 | } 61 | 62 | @Override 63 | public boolean contains(@Nullable Object element) { 64 | if (MoreCollections.safeContains(unfiltered, element)) { 65 | @SuppressWarnings("unchecked") // element is in unfiltered, so it must be an E 66 | E e = (E) element; 67 | return predicate.apply(e); 68 | } 69 | return false; 70 | } 71 | 72 | @Override 73 | public boolean containsAll(Collection collection) { 74 | return MoreCollections.containsAllImpl(this, collection); 75 | } 76 | 77 | @Override 78 | public boolean isEmpty() { 79 | return !Iterables.any(unfiltered, predicate); 80 | } 81 | 82 | @Override 83 | public Iterator iterator() { 84 | return Iterators.filter(unfiltered.iterator(), predicate); 85 | } 86 | 87 | @Override 88 | public boolean remove(Object element) { 89 | return contains(element) && unfiltered.remove(element); 90 | } 91 | 92 | @Override 93 | public boolean removeAll(final Collection collection) { 94 | return Iterables.removeIf(unfiltered, Predicates.and(predicate, Predicates.in(collection))); 95 | } 96 | 97 | @Override 98 | public boolean retainAll(final Collection collection) { 99 | return Iterables.removeIf(unfiltered, 100 | Predicates.and(predicate, Predicates.not(Predicates.in(collection)))); 101 | } 102 | 103 | @Override 104 | public int size() { 105 | return Iterators.size(iterator()); 106 | } 107 | 108 | @Override 109 | public Object[] toArray() { 110 | // creating an ArrayList so filtering happens once 111 | return Lists.newArrayList(iterator()).toArray(); 112 | } 113 | 114 | @Override 115 | public T[] toArray(T[] array) { 116 | return Lists.newArrayList(iterator()).toArray(array); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/MoreArrays.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import java.lang.reflect.Array; 19 | import java.util.Arrays; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | /** 23 | * Static utility methods pertaining to object arrays. 24 | * 25 | * @author Kevin Bourrillion 26 | * @since 2.0 (imported from Google Collections Library) 27 | */ 28 | public final class MoreArrays { 29 | 30 | /** 31 | * Returns a new array of the given length with the specified component type. 32 | * 33 | * @param type the component type 34 | * @param length the length of the new array 35 | */ 36 | @SuppressWarnings("unchecked") 37 | public static T[] newArray(Class type, int length) { 38 | return (T[]) Array.newInstance(type, length); 39 | } 40 | 41 | /** 42 | * Returns a new array of the given length with the same type as a reference 43 | * array. 44 | * 45 | * @param reference any array of the desired type 46 | * @param length the length of the new array 47 | */ 48 | public static T[] newArray(T[] reference, int length) { 49 | Class type = reference.getClass().getComponentType(); 50 | // the cast is safe because 51 | // result.getClass() == reference.getClass().getComponentType() 52 | return (T[]) Array.newInstance(type, length); 53 | } 54 | 55 | /** 56 | * Returns a new array that contains the concatenated contents of two arrays. 57 | * 58 | * @param first the first array of elements to concatenate 59 | * @param second the second array of elements to concatenate 60 | * @param type the component type of the returned array 61 | */ 62 | public static T[] concat(T[] first, T[] second, Class type) { 63 | T[] result = newArray(type, first.length + second.length); 64 | System.arraycopy(first, 0, result, 0, first.length); 65 | System.arraycopy(second, 0, result, first.length, second.length); 66 | return result; 67 | } 68 | 69 | /** 70 | * Returns a new array that prepends {@code element} to {@code array}. 71 | * 72 | * @param element the element to prepend to the front of {@code array} 73 | * @param array the array of elements to append 74 | * @return an array whose size is one larger than {@code array}, with 75 | * {@code element} occupying the first position, and the 76 | * elements of {@code array} occupying the remaining elements. 77 | */ 78 | public static T[] concat(@Nullable T element, T[] array) { 79 | T[] result = newArray(array, array.length + 1); 80 | result[0] = element; 81 | System.arraycopy(array, 0, result, 1, array.length); 82 | return result; 83 | } 84 | 85 | /** 86 | * Returns a new array that appends {@code element} to {@code array}. 87 | * 88 | * @param array the array of elements to prepend 89 | * @param element the element to append to the end 90 | * @return an array whose size is one larger than {@code array}, with 91 | * the same contents as {@code array}, plus {@code element} occupying the 92 | * last position. 93 | */ 94 | public static T[] concat(T[] array, @Nullable T element) { 95 | T[] result = Arrays.copyOf(array, array.length + 1); 96 | result[array.length] = element; 97 | return result; 98 | } 99 | 100 | @Nullable 101 | public static T firstNonNull(T... nullableItems) { 102 | for (T item : nullableItems) { 103 | if (item != null) { 104 | return item; 105 | } 106 | } 107 | return null; 108 | } 109 | 110 | private MoreArrays() { 111 | // no instances 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/functions/Functions.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.functions; 17 | 18 | import com.fernandocejas.arrow.objects.MoreObjects; 19 | import java.io.Serializable; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 23 | 24 | /** 25 | * Static utility methods pertaining to {@code Function} instances. 26 | *

27 | *

All methods return serializable functions as long as they're given serializable parameters. 28 | *

29 | *

See the Guava User Guide article on the use of {@code 31 | * Function}. 32 | * 33 | * @author Mike Bostock 34 | * @author Jared Levy 35 | * @since 2.0 (imported from Google Collections Library) 36 | * 37 | *

This class contains code derived from Google 38 | * Guava 39 | */ 40 | public final class Functions { 41 | 42 | /** 43 | * Returns a function that calls {@code toString()} on its argument. The function does not accept 44 | * nulls; it will throw a {@link NullPointerException} when applied to {@code null}. 45 | *

46 | *

Warning: The returned function may not be consistent with equals (as 47 | * documented at {@link Function#apply}). For example, this function yields different results for 48 | * the two equal instances {@code ImmutableSet.of(1, 2)} and {@code ImmutableSet.of(2, 1)}. 49 | */ 50 | public static Function toStringFunction() { 51 | return ToStringFunction.INSTANCE; 52 | } 53 | 54 | // enum singleton pattern 55 | private enum ToStringFunction implements Function { 56 | INSTANCE; 57 | 58 | @Override 59 | public String apply(Object o) { 60 | if (o != null) { 61 | return o.toString(); 62 | } else { 63 | throw new NullPointerException(); 64 | } 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | return "toString"; 70 | } 71 | } 72 | 73 | /** 74 | * Returns the identity function. 75 | */ 76 | // implementation is "fully variant"; E has become a "pass-through" type 77 | @SuppressWarnings("unchecked") 78 | public static Function identity() { 79 | return (Function) IdentityFunction.INSTANCE; 80 | } 81 | 82 | private enum IdentityFunction implements Function { 83 | INSTANCE; 84 | 85 | @Override 86 | public Object apply(Object o) { 87 | checkNotNull(o); 88 | return o; 89 | } 90 | 91 | @Override 92 | public String toString() { 93 | return "identity"; 94 | } 95 | } 96 | 97 | /** 98 | * Creates a function that returns {@code value} for any input. 99 | * 100 | * @param value the constant value for the function to return 101 | * @return a function that always returns {@code value} 102 | */ 103 | public static Function constant(@Nullable E value) { 104 | return new ConstantFunction<>(value); 105 | } 106 | 107 | private static class ConstantFunction implements Function, Serializable { 108 | private static final long serialVersionUID = 0; 109 | 110 | private final E value; 111 | 112 | public ConstantFunction(@Nullable E value) { 113 | this.value = value; 114 | } 115 | 116 | @Override 117 | public E apply(Object from) { 118 | checkNotNull(from); 119 | return value; 120 | } 121 | 122 | @Override 123 | public boolean equals(@Nullable Object obj) { 124 | if (obj instanceof ConstantFunction) { 125 | ConstantFunction that = (ConstantFunction) obj; 126 | return MoreObjects.equal(value, that.value); 127 | } 128 | return false; 129 | } 130 | 131 | @Override 132 | public int hashCode() { 133 | return (value == null) ? 0 : value.hashCode(); 134 | } 135 | 136 | @Override 137 | public String toString() { 138 | return "constant(" + value + ")"; 139 | } 140 | } 141 | 142 | private Functions() { 143 | // no instances 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Arrow 4 | ========================= 5 | 6 | [![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0) 7 | [![Platform](https://img.shields.io/badge/platform-java-green.svg)](http://www.oracle.com/technetwork/indexes/downloads/index.html) 8 | [![Download](https://api.bintray.com/packages/android10/maven/arrow/images/download.svg) ](https://bintray.com/android10/maven/arrow/_latestVersion) 9 | 10 | ```Arrow``` is Lightweight library toolbox for Java and Android Development. Basically it groups utilites and helper classes commonly used for mobile development. Most of them have been extracted from popular java libraries like ```Guava``` or ```Apache Commons``` plus other stuff added myself. Refer to the Main Features section for a fully explanation of its capabilities. 11 | 12 | ![arrow](https://cloud.githubusercontent.com/assets/1624385/13253864/9852185c-da3e-11e5-93ff-e7d21e130130.jpg) 13 | 14 | 15 | # Features: 16 | 17 | - **```Optional```:** An immutable object that may contain a non-null reference to another object. Each instance of this type either contains a non-null reference, or contains nothing (in which case we say that the reference is "absent"); it is never said to "contain null". Refer to Guava ```Optional``` documentation or How to use ```Optional``` on Java and Android. 18 | 19 | - **```Strings```:** Static utility methods pertaining to String or CharSequence instances. Refer to Guava ```Strings``` documentation. 20 | 21 | - **```Preconditions```:** Static convenience methods that help a method or constructor check whether it was invoked correctly (whether its preconditions have been met). These methods generally accept a boolean expression which is expected to be true (or in the case of checkNotNull, an object reference which is expected to be non-null). When false (or null) is passed instead, the Preconditions method throws an unchecked exception, which helps the calling method communicate to its caller that that caller has made a mistake. Refer to Guava ```Preconditions``` documentation. 22 | 23 | - **```Collections```:** Provides static methods for working with Collection instances. Refer to Guava ```Collections``` documentation. 24 | - ```FilteredCollection.class``` 25 | - ```Lists.class``` 26 | - ```CollectPreconditions.class``` 27 | - ```Iterables.class``` 28 | - ```Iterators.class``` 29 | - ```MoreArrays.class``` 30 | - ```MoreCollections.class``` 31 | 32 | - **```MoreObjects```:** Helper functions that operate on any Object, and are not already provided in ```Objects```. Refer to Guava ```MoreObjects``` documentation. 33 | 34 | - **```Annotations```:** These annotations has no side effect in your code, they are only used for decoration purpose, in case you need either to highlight it or to denotate it. 35 | - ```@Beta```: Class, method or field is declared as Beta functionality 36 | - ```@Experimental```: Class, method or field is declared as Experimental 37 | - ```@Issue```: Class, method or field is linked to an issue. A ref value can be added to specify more information. 38 | - ```@See```: Class, method or field is linked to a link. A ref value should be added in order to specify the link url. 39 | - ```@VisibleForTesting```: Class, method or field has its visibility relaxed, so that it is more widely visible than otherwise necessary to make code testable. 40 | - ```@WorkInProgress```: Class, method or field is declared as work in progress. 41 | 42 | 43 | # Using Arrow 44 | 45 | To enable Arrow, add your dependency in your ```build.gradle``` file: 46 | 47 | ```java 48 | repositories { 49 | jcenter() 50 | } 51 | 52 | dependencies { 53 | compile 'com.fernandocejas:arrow:{latest_version}' 54 | } 55 | ``` 56 | 57 | 58 | # License 59 | 60 | Copyright 2016 Fernando Cejas 61 | 62 | Licensed under the Apache License, Version 2.0 (the "License"); 63 | you may not use this file except in compliance with the License. 64 | You may obtain a copy of the License at 65 | 66 | http://www.apache.org/licenses/LICENSE-2.0 67 | 68 | Unless required by applicable law or agreed to in writing, software 69 | distributed under the License is distributed on an "AS IS" BASIS, 70 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 71 | See the License for the specific language governing permissions and 72 | limitations under the License. 73 | 74 | 75 | ![http://www.fernandocejas.com](https://github.com/android10/Sample-Data/blob/master/android10/android10_logo_big.png) 76 | 77 | Buy Me A Coffee 78 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/ReverseList.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import java.util.AbstractList; 19 | import java.util.Iterator; 20 | import java.util.List; 21 | import java.util.ListIterator; 22 | import java.util.NoSuchElementException; 23 | import org.jetbrains.annotations.Nullable; 24 | 25 | import static com.fernandocejas.arrow.checks.Preconditions.checkElementIndex; 26 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 27 | import static com.fernandocejas.arrow.checks.Preconditions.checkPositionIndex; 28 | import static com.fernandocejas.arrow.checks.Preconditions.checkPositionIndexes; 29 | import static com.fernandocejas.arrow.checks.Preconditions.checkState; 30 | 31 | class ReverseList extends AbstractList { 32 | private final List forwardList; 33 | 34 | ReverseList(List forwardList) { 35 | this.forwardList = checkNotNull(forwardList); 36 | } 37 | 38 | List getForwardList() { 39 | return forwardList; 40 | } 41 | 42 | private int reverseIndex(int index) { 43 | int size = size(); 44 | checkElementIndex(index, size); 45 | return size - 1 - index; 46 | } 47 | 48 | private int reversePosition(int index) { 49 | int size = size(); 50 | checkPositionIndex(index, size); 51 | return size - index; 52 | } 53 | 54 | @Override 55 | public void add(int index, @Nullable T element) { 56 | forwardList.add(reversePosition(index), element); 57 | } 58 | 59 | @Override 60 | public void clear() { 61 | forwardList.clear(); 62 | } 63 | 64 | @Override 65 | public T remove(int index) { 66 | return forwardList.remove(reverseIndex(index)); 67 | } 68 | 69 | @Override 70 | protected void removeRange(int fromIndex, int toIndex) { 71 | subList(fromIndex, toIndex).clear(); 72 | } 73 | 74 | @Override 75 | public T set(int index, @Nullable T element) { 76 | return forwardList.set(reverseIndex(index), element); 77 | } 78 | 79 | @Override 80 | public T get(int index) { 81 | return forwardList.get(reverseIndex(index)); 82 | } 83 | 84 | @Override 85 | public int size() { 86 | return forwardList.size(); 87 | } 88 | 89 | @Override 90 | public List subList(int fromIndex, int toIndex) { 91 | checkPositionIndexes(fromIndex, toIndex, size()); 92 | return Lists.reverse(forwardList.subList( 93 | reversePosition(toIndex), reversePosition(fromIndex))); 94 | } 95 | 96 | @Override 97 | public Iterator iterator() { 98 | return listIterator(); 99 | } 100 | 101 | @Override 102 | public ListIterator listIterator(int index) { 103 | int start = reversePosition(index); 104 | final ListIterator forwardIterator = forwardList.listIterator(start); 105 | return new ReverseListIterator<>(forwardIterator); 106 | } 107 | 108 | private class ReverseListIterator implements ListIterator { 109 | 110 | private final ListIterator forwardIterator; 111 | boolean canRemoveOrSet; 112 | 113 | public ReverseListIterator(ListIterator forwardIterator) { 114 | this.forwardIterator = forwardIterator; 115 | } 116 | 117 | @Override 118 | public void add(T e) { 119 | forwardIterator.add(e); 120 | forwardIterator.previous(); 121 | canRemoveOrSet = false; 122 | } 123 | 124 | @Override 125 | public boolean hasNext() { 126 | return forwardIterator.hasPrevious(); 127 | } 128 | 129 | @Override 130 | public boolean hasPrevious() { 131 | return forwardIterator.hasNext(); 132 | } 133 | 134 | @Override 135 | public T next() { 136 | if (!hasNext()) { 137 | throw new NoSuchElementException(); 138 | } 139 | canRemoveOrSet = true; 140 | return forwardIterator.previous(); 141 | } 142 | 143 | @Override 144 | public int nextIndex() { 145 | return reversePosition(forwardIterator.nextIndex()); 146 | } 147 | 148 | @Override 149 | public T previous() { 150 | if (!hasPrevious()) { 151 | throw new NoSuchElementException(); 152 | } 153 | canRemoveOrSet = true; 154 | return forwardIterator.next(); 155 | } 156 | 157 | @Override 158 | public int previousIndex() { 159 | return nextIndex() - 1; 160 | } 161 | 162 | @Override 163 | public void remove() { 164 | forwardIterator.remove(); 165 | canRemoveOrSet = false; 166 | } 167 | 168 | @Override 169 | public void set(T e) { 170 | checkState(canRemoveOrSet); 171 | forwardIterator.set(e); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/MoreCollections.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import com.fernandocejas.arrow.functions.Predicate; 19 | import com.fernandocejas.arrow.strings.Joiner; 20 | import com.fernandocejas.arrow.strings.Strings; 21 | import java.util.Collection; 22 | import org.jetbrains.annotations.Nullable; 23 | 24 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 25 | import static com.fernandocejas.arrow.functions.Predicates.in; 26 | 27 | /** 28 | * Provides static methods for working with {@code Collection} instances. 29 | * 30 | * @author Chris Povirk 31 | * @author Mike Bostock 32 | * @author Jared Levy 33 | * @since 2.0 (imported from Google Collections Library) 34 | */ 35 | public final class MoreCollections { 36 | 37 | static final Joiner STANDARD_JOINER = Strings.joinOn(", ").useForNull("null"); 38 | 39 | /** 40 | * Delegates to {@link Collection#contains}. Returns {@code false} if the 41 | * {@code contains} method throws a {@code ClassCastException} or 42 | * {@code NullPointerException}. 43 | */ 44 | @SuppressWarnings("PMD.AvoidCatchingNPE") 45 | static boolean safeContains(Collection collection, @Nullable Object object) { 46 | checkNotNull(collection); 47 | try { 48 | return collection.contains(object); 49 | } catch (ClassCastException e) { 50 | return false; 51 | } catch (NullPointerException e) { 52 | return false; 53 | } 54 | } 55 | 56 | /** 57 | * Returns the elements of {@code unfiltered} that satisfy a predicate. The 58 | * returned collection is a live view of {@code unfiltered}; changes to one 59 | * affect the other. 60 | * 61 | *

The resulting collection's iterator does not support {@code remove()}, 62 | * but all other collection methods are supported. When given an element that 63 | * doesn't satisfy the predicate, the collection's {@code add()} and {@code 64 | * addAll()} methods throw an {@link IllegalArgumentException}. When methods 65 | * such as {@code removeAll()} and {@code clear()} are called on the filtered 66 | * collection, only elements that satisfy the filter will be removed from the 67 | * underlying collection. 68 | * 69 | *

The returned collection isn't threadsafe or serializable, even if 70 | * {@code unfiltered} is. 71 | * 72 | *

Many of the filtered collection's methods, such as {@code size()}, 73 | * iterate across every element in the underlying collection and determine 74 | * which elements satisfy the filter. When a live view is not needed, 75 | * it may be faster to copy {@code Iterables.filter(unfiltered, predicate)} 76 | * and use the copy. 77 | * 78 | *

Warning: {@code predicate} must be consistent with equals, 79 | * as documented at {@link Predicate#apply}. Do not provide a predicate such 80 | * as {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent 81 | * with equals. 82 | */ 83 | // TODO(kevinb): how can we omit that Iterables link when building gwt 84 | // javadoc? 85 | public static Collection filter( 86 | Collection unfiltered, Predicate predicate) { 87 | if (unfiltered instanceof FilteredCollection) { 88 | // Support clear(), removeAll(), and retainAll() when filtering a filtered 89 | // collection. 90 | return ((FilteredCollection) unfiltered).createCombined(predicate); 91 | } 92 | 93 | return new FilteredCollection<>(checkNotNull(unfiltered), checkNotNull(predicate)); 94 | } 95 | 96 | /** 97 | * Returns {@code true} if the collection {@code self} contains all of the 98 | * elements in the collection {@code c}. 99 | * 100 | *

This method iterates over the specified collection {@code c}, checking 101 | * each element returned by the iterator in turn to see if it is contained in 102 | * the specified collection {@code self}. If all elements are so contained, 103 | * {@code true} is returned, otherwise {@code false}. 104 | * 105 | * @param self a collection which might contain all elements in {@code c} 106 | * @param c a collection whose elements might be contained by {@code self} 107 | */ 108 | static boolean containsAllImpl(Collection self, Collection c) { 109 | return Iterables.all(c, in(self)); 110 | } 111 | 112 | /** 113 | * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557 114 | */ 115 | static Collection cast(Iterable iterable) { 116 | return (Collection) iterable; 117 | } 118 | 119 | private MoreCollections() { 120 | // no instances 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /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 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/AbstractIterator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import java.util.NoSuchElementException; 19 | 20 | import static com.fernandocejas.arrow.checks.Preconditions.checkState; 21 | 22 | /** 23 | * This class provides a skeletal implementation of the {@code Iterator} 24 | * interface, to make this interface easier to implement for certain types of 25 | * data sources. 26 | * 27 | *

{@code Iterator} requires its implementations to support querying the 28 | * end-of-data status without changing the iterator's state, using the {@link 29 | * #hasNext} method. But many data sources, such as {@link 30 | * java.io.Reader#read()}, do not expose this information; the only way to 31 | * discover whether there is any data left is by trying to retrieve it. These 32 | * types of data sources are ordinarily difficult to write iterators for. But 33 | * using this class, one must implement only the {@link #computeNext} method, 34 | * and invoke the {@link #endOfData} method when appropriate. 35 | * 36 | *

Another example is an iterator that skips over null elements in a backing 37 | * iterator. This could be implemented as:

   {@code
 38 |  *
 39 |  *   public static Iterator skipNulls(final Iterator in) {
 40 |  *     return new AbstractIterator() {
 41 |  *       protected String computeNext() {
 42 |  *         while (in.hasNext()) {
 43 |  *           String s = in.next();
 44 |  *           if (s != null) {
 45 |  *             return s;
 46 |  *           }
 47 |  *         }
 48 |  *         return endOfData();
 49 |  *       }
 50 |  *     };
 51 |  *   }}
52 | * 53 | *

This class supports iterators that include null elements. 54 | * 55 | * @author Kevin Bourrillion 56 | * @since 2.0 (imported from Google Collections Library) 57 | * 58 | *

This class contains code derived from Google 59 | * Guava 60 | */ 61 | public abstract class AbstractIterator extends UnmodifiableIterator { 62 | private State state = State.NOT_READY; 63 | private T next; 64 | 65 | /** 66 | * Constructor for use by subclasses. 67 | */ 68 | protected AbstractIterator() { 69 | } 70 | 71 | private enum State { 72 | /** 73 | * We have computed the next element and haven't returned it yet. 74 | */ 75 | READY, 76 | 77 | /** 78 | * We haven't yet computed or have already returned the element. 79 | */ 80 | NOT_READY, 81 | 82 | /** 83 | * We have reached the end of the data and are finished. 84 | */ 85 | DONE, 86 | 87 | /** 88 | * We've suffered an exception and are kaput. 89 | */ 90 | FAILED, 91 | } 92 | 93 | /** 94 | * Returns the next element. Note: the implementation must call {@link 95 | * #endOfData()} when there are no elements left in the iteration. Failure to 96 | * do so could result in an infinite loop. 97 | * 98 | *

The initial invocation of {@link #hasNext()} or {@link #next()} calls 99 | * this method, as does the first invocation of {@code hasNext} or {@code 100 | * next} following each successful call to {@code next}. Once the 101 | * implementation either invokes {@code endOfData} or throws an exception, 102 | * {@code computeNext} is guaranteed to never be called again. 103 | * 104 | *

If this method throws an exception, it will propagate outward to the 105 | * {@code hasNext} or {@code next} invocation that invoked this method. Any 106 | * further attempts to use the iterator will result in an {@link 107 | * IllegalStateException}. 108 | * 109 | *

The implementation of this method may not invoke the {@code hasNext}, 110 | * {@code next}, or {@link #peek()} methods on this instance; if it does, an 111 | * {@code IllegalStateException} will result. 112 | * 113 | * @return the next element if there was one. If {@code endOfData} was called 114 | * during execution, the return value will be ignored. 115 | * @throws RuntimeException if any unrecoverable error happens. This exception 116 | * will propagate outward to the {@code hasNext()}, {@code next()}, or 117 | * {@code peek()} invocation that invoked this method. Any further 118 | * attempts to use the iterator will result in an 119 | * {@link IllegalStateException}. 120 | */ 121 | protected abstract T computeNext(); 122 | 123 | /** 124 | * Implementations of {@link #computeNext} must invoke this method when 125 | * there are no elements left in the iteration. 126 | * 127 | * @return {@code null}; a convenience so your {@code computeNext} 128 | * implementation can use the simple statement {@code return endOfData();} 129 | */ 130 | protected final T endOfData() { 131 | state = State.DONE; 132 | return null; 133 | } 134 | 135 | @Override 136 | public final boolean hasNext() { 137 | checkState(state != State.FAILED); 138 | switch (state) { 139 | case DONE: 140 | return false; 141 | case READY: 142 | return true; 143 | default: 144 | } 145 | return tryToComputeNext(); 146 | } 147 | 148 | private boolean tryToComputeNext() { 149 | state = State.FAILED; // temporary pessimism 150 | next = computeNext(); 151 | if (state != State.DONE) { 152 | state = State.READY; 153 | return true; 154 | } 155 | return false; 156 | } 157 | 158 | @Override 159 | public final T next() { 160 | if (!hasNext()) { 161 | throw new NoSuchElementException(); 162 | } 163 | state = State.NOT_READY; 164 | T result = next; 165 | next = null; 166 | return result; 167 | } 168 | 169 | /** 170 | * Returns the next element in the iteration without advancing the iteration. 171 | * 172 | *

Implementations of {@code AbstractIterator} that wish to expose this 173 | * functionality should implement {@code PeekingIterator}. 174 | */ 175 | public final T peek() { 176 | if (!hasNext()) { 177 | throw new NoSuchElementException(); 178 | } 179 | return next; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/Lists.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collection; 20 | import java.util.Collections; 21 | import java.util.Iterator; 22 | import java.util.LinkedList; 23 | import java.util.List; 24 | import java.util.RandomAccess; 25 | 26 | import static com.fernandocejas.arrow.checks.Preconditions.checkArgument; 27 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 28 | 29 | /** 30 | * Static utility methods pertaining to {@link List} instances. 31 | * 32 | *

See the Guava User Guide article on 34 | * {@code Lists}. 35 | * 36 | * @author Kevin Bourrillion 37 | * @author Mike Bostock 38 | * @author Louis Wasserman 39 | * @since 2.0 (imported from Google Collections Library) 40 | * 41 | *

This class contains code derived from Google Guava 42 | */ 43 | public final class Lists { 44 | /** 45 | * Creates a mutable {@code ArrayList} instance containing the given 46 | * elements. 47 | * 48 | *

Note: essentially the only reason to use this method is when you 49 | * will need to add or remove elements later. If any elements 50 | * might be null, or you need support for {@link List#set(int, Object)}, use 51 | * {@link java.util.Arrays#asList}. 52 | * 53 | *

Note that even when you do need the ability to add or remove, this method 54 | * provides only a tiny bit of syntactic sugar for {@code newArrayList(}{@link 55 | * java.util.Arrays#asList asList}{@code (...))}, or for creating an empty list then 56 | * calling {@link Collections#addAll}. This method is not actually very useful 57 | * and will likely be deprecated in the future. 58 | */ 59 | @SuppressWarnings({"unchecked", "PMD.LooseCoupling"}) 60 | public static ArrayList newArrayList(E... elements) { 61 | checkNotNull(elements); 62 | ArrayList list = new ArrayList<>(elements.length); 63 | Collections.addAll(list, elements); 64 | return list; 65 | } 66 | 67 | /** 68 | * Creates a mutable {@code ArrayList} instance containing the given 69 | * elements; a very thin shortcut for creating an empty list then calling 70 | * {@link Iterables#addAll}. 71 | * 72 | *

Note for Java 7 and later: if {@code elements} is a {@link 73 | * Collection}, you don't need this method. Use the {@code ArrayList} 74 | * {@linkplain ArrayList#ArrayList(Collection) constructor} directly, taking 75 | * advantage of the new "diamond" syntax. 76 | */ 77 | @SuppressWarnings("PMD.LooseCoupling") // we want the concrete type 78 | public static ArrayList newArrayList(Iterable elements) { 79 | checkNotNull(elements); // for GWT 80 | // Let ArrayList's sizing logic work, if possible 81 | return elements instanceof Collection 82 | ? new ArrayList<>(MoreCollections.cast(elements)) 83 | : newArrayList(elements.iterator()); 84 | } 85 | 86 | /** 87 | * Creates a mutable {@code ArrayList} instance containing the given 88 | * elements; a very thin shortcut for creating an empty list and then calling 89 | * {@link Iterators#addAll}. 90 | */ 91 | @SuppressWarnings("PMD.LooseCoupling") // we want the concrete type 92 | public static ArrayList newArrayList(Iterator elements) { 93 | final ArrayList list = new ArrayList<>(); 94 | Iterators.addAll(list, elements); 95 | return list; 96 | } 97 | 98 | /** 99 | * Creates a mutable {@code ArrayList} instance containing the given 100 | * primitive elements. 101 | */ 102 | @SuppressWarnings("PMD.LooseCoupling") // we want the concrete type 103 | public static ArrayList newArrayList(int[] elements) { 104 | final ArrayList list = new ArrayList<>(elements.length); 105 | for (int el : elements) { 106 | list.add(el); 107 | } 108 | return list; 109 | } 110 | 111 | /** 112 | * Creates a mutable {@code LinkedList} instance containing the given 113 | * elements; a very thin shortcut for creating an empty list then calling 114 | * {@link Iterables#addAll}. 115 | * 116 | *

Performance note: {@link ArrayList} and {@link 117 | * java.util.ArrayDeque} consistently outperform {@code LinkedList} except in 118 | * certain rare and specific situations. Unless you have spent a lot of time 119 | * benchmarking your specific needs, use one of those instead. 120 | * 121 | *

Note for Java 7 and later: if {@code elements} is a {@link 122 | * Collection}, you don't need this method. Use the {@code LinkedList} 123 | * {@linkplain LinkedList#LinkedList(Collection) constructor} directly, taking 124 | * advantage of the new "diamond" syntax. 125 | */ 126 | @SuppressWarnings("PMD.LooseCoupling") // we want the concrete type 127 | public static LinkedList newLinkedList(Iterable elements) { 128 | LinkedList list = new LinkedList<>(); 129 | Iterables.addAll(list, elements); 130 | return list; 131 | } 132 | 133 | /** 134 | * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557 135 | */ 136 | static List cast(Iterable iterable) { 137 | return (List) iterable; 138 | } 139 | 140 | /** 141 | * Returns consecutive {@linkplain List#subList(int, int) sublists} of a list, 142 | * each of the same size (the final list may be smaller). For example, 143 | * partitioning a list containing {@code [a, b, c, d, e]} with a partition 144 | * size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer list containing 145 | * two inner lists of three and two elements, all in the original order. 146 | * 147 | *

The outer list is unmodifiable, but reflects the latest state of the 148 | * source list. The inner lists are sublist views of the original list, 149 | * produced on demand using {@link List#subList(int, int)}, and are subject 150 | * to all the usual caveats about modification as explained in that API. 151 | * 152 | * @param list the list to return consecutive sublists of 153 | * @param size the desired size of each sublist (the last may be 154 | * smaller) 155 | * @return a list of consecutive sublists 156 | * @throws IllegalArgumentException if {@code partitionSize} is nonpositive 157 | */ 158 | public static List> partition(List list, int size) { 159 | checkNotNull(list); 160 | checkArgument(size > 0); 161 | return list instanceof RandomAccess 162 | ? new RandomAccessPartition<>(list, size) 163 | : new Partition<>(list, size); 164 | } 165 | 166 | /** 167 | * Returns a reversed view of the specified list. For example, {@code 168 | * Lists.reverse(Arrays.asList(1, 2, 3))} returns a list containing {@code 3, 169 | * 2, 1}. The returned list is backed by this list, so changes in the returned 170 | * list are reflected in this list, and vice-versa. The returned list supports 171 | * all of the optional list operations supported by this list. 172 | *

173 | *

The returned list is random-access if the specified list is random 174 | * access. 175 | * 176 | * @since 7.0 177 | */ 178 | public static List reverse(List list) { 179 | if (list instanceof ReverseList) { 180 | return ((ReverseList) list).getForwardList(); 181 | } else if (list instanceof RandomAccess) { 182 | return new RandomAccessReverseList<>(list); 183 | } else { 184 | return new ReverseList<>(list); 185 | } 186 | } 187 | 188 | private Lists() { 189 | // no instances 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/optional/Optional.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2011 The Guava Authors 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 | package com.fernandocejas.arrow.optional; 17 | 18 | import com.fernandocejas.arrow.collections.AbstractIterator; 19 | import com.fernandocejas.arrow.functions.Function; 20 | import java.io.Serializable; 21 | import java.util.Iterator; 22 | import java.util.Set; 23 | import org.jetbrains.annotations.Nullable; 24 | 25 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 26 | 27 | /** 28 | * An immutable object that may contain a non-null reference to another object. Each 29 | * instance of this type either contains a non-null reference, or contains nothing (in 30 | * which case we say that the reference is "absent"); it is never said to "contain {@code 31 | * null}". 32 | * 33 | *

A non-null {@code Optional} reference can be used as a replacement for a nullable 34 | * {@code T} reference. It allows you to represent "a {@code T} that must be present" and 35 | * a "a {@code T} that might be absent" as two distinct types in your program, which can 36 | * aid clarity. 37 | * 38 | *

Some uses of this class include 39 | * 40 | *

    41 | *
  • As a method return type, as an alternative to returning {@code null} to indicate 42 | * that no value was available 43 | *
  • To distinguish between "unknown" (for example, not present in a map) and "known to 44 | * have no value" (present in the map, with value {@code Optional.absent()}) 45 | *
  • To wrap nullable references for storage in a collection that does not support 46 | * {@code null} (though there are 47 | * 48 | * several other approaches to this that should be considered first) 49 | *
50 | * 51 | *

A common alternative to using this class is to find or create a suitable 52 | * null object for the 53 | * type in question. 54 | * 55 | *

This class is not intended as a direct analogue of any existing "option" or "maybe" 56 | * construct from other programming environments, though it may bear some similarities. 57 | * 58 | *

See the Guava User Guide article on 60 | * using {@code Optional}. 61 | * 62 | * @param the type of instance that can be contained. {@code Optional} is naturally 63 | * covariant on this type, so it is safe to cast an {@code Optional} to {@code 64 | * Optional} for any supertype {@code S} of {@code T}. 65 | * @author Kurt Alfred Kluever 66 | * @author Kevin Bourrillion 67 | * @since 10.0 68 | * 69 | *

This class contains code derived from Google 70 | * Guava 71 | */ 72 | public abstract class Optional implements Serializable { 73 | private static final long serialVersionUID = 0; 74 | 75 | /** 76 | * Returns an {@code Optional} instance with no contained reference. 77 | */ 78 | public static Optional absent() { 79 | return Absent.withType(); 80 | } 81 | 82 | /** 83 | * Returns an {@code Optional} instance containing the given non-null reference. 84 | */ 85 | public static Optional of(T reference) { 86 | return new Present<>(checkNotNull(reference)); 87 | } 88 | 89 | /** 90 | * If {@code nullableReference} is non-null, returns an {@code Optional} instance containing that 91 | * reference; otherwise returns {@link Optional#absent}. 92 | */ 93 | public static Optional fromNullable(@Nullable T nullableReference) { 94 | return (nullableReference == null) 95 | ? Optional.absent() 96 | : new Present<>(nullableReference); 97 | } 98 | 99 | Optional() { 100 | } 101 | 102 | /** 103 | * Returns {@code true} if this holder contains a (non-null) instance. 104 | */ 105 | public abstract boolean isPresent(); 106 | 107 | /** 108 | * Returns the contained instance, which must be present. If the instance might be 109 | * absent, use {@link #or(Object)} or {@link #orNull} instead. 110 | * 111 | * @throws IllegalStateException if the instance is absent ({@link #isPresent} returns 112 | * {@code false}) 113 | */ 114 | public abstract T get(); 115 | 116 | /** 117 | * Returns the contained instance if it is present; {@code defaultValue} otherwise. If 118 | * no default value should be required because the instance is known to be present, use 119 | * {@link #get()} instead. For a default value of {@code null}, use {@link #orNull}. 120 | * 121 | *

Note about generics: The signature {@code public T or(T defaultValue)} is overly 122 | * restrictive. However, the ideal signature, {@code public S or(S)}, is not legal 123 | * Java. As a result, some sensible operations involving subtypes are compile errors: 124 | *

   {@code
125 |    *
126 |    *   Optional optionalInt = getSomeOptionalInt();
127 |    *   Number value = optionalInt.or(0.5); // error
128 |    *
129 |    *   FluentIterable numbers = getSomeNumbers();
130 |    *   Optional first = numbers.first();
131 |    *   Number value = first.or(0.5); // error}
132 | * 133 | *

As a workaround, it is always safe to cast an {@code Optional} to {@code 134 | * Optional}. Casting either of the above example {@code Optional} instances to {@code 135 | * Optional} (where {@code Number} is the desired output type) solves the problem: 136 | *

   {@code
137 |    *
138 |    *   Optional optionalInt = (Optional) getSomeOptionalInt();
139 |    *   Number value = optionalInt.or(0.5); // fine
140 |    *
141 |    *   FluentIterable numbers = getSomeNumbers();
142 |    *   Optional first = (Optional) numbers.first();
143 |    *   Number value = first.or(0.5); // fine}
144 | */ 145 | public abstract T or(T defaultValue); 146 | 147 | /** 148 | * Returns this {@code Optional} if it has a value present; {@code secondChoice} 149 | * otherwise. 150 | */ 151 | public abstract Optional or(Optional secondChoice); 152 | 153 | /** 154 | * Returns the contained instance if it is present; {@code null} otherwise. If the 155 | * instance is known to be present, use {@link #get()} instead. 156 | */ 157 | @Nullable 158 | public abstract T orNull(); 159 | 160 | /** 161 | * Returns an immutable singleton {@link Set} whose only element is the contained instance 162 | * if it is present; an empty immutable {@link Set} otherwise. 163 | * 164 | * @since 11.0 165 | */ 166 | public abstract Set asSet(); 167 | 168 | /** 169 | * If the instance is present, it is transformed with the given {@link Function}; otherwise, 170 | * {@link Optional#absent} is returned. If the function returns {@code null}, a 171 | * {@link NullPointerException} is thrown. 172 | * 173 | * @throws NullPointerException if the function returns {@code null} 174 | * @since 12.0 175 | */ 176 | public abstract Optional transform(Function function); 177 | 178 | /** 179 | * Returns {@code true} if {@code object} is an {@code Optional} instance, and either 180 | * the contained references are {@linkplain Object#equals equal} to each other or both 181 | * are absent. Note that {@code Optional} instances of differing parameterized types can 182 | * be equal. 183 | */ 184 | @Override 185 | public abstract boolean equals(@Nullable Object object); 186 | 187 | /** 188 | * Returns a hash code for this instance. 189 | */ 190 | @Override 191 | public abstract int hashCode(); 192 | 193 | /** 194 | * Returns a string representation for this instance. The form of this string 195 | * representation is unspecified. 196 | */ 197 | @Override 198 | public abstract String toString(); 199 | 200 | /** 201 | * Returns the value of each present instance from the supplied {@code optionals}, in order, 202 | * skipping over occurrences of {@link Optional#absent}. Iterators are unmodifiable and are 203 | * evaluated lazily. 204 | * 205 | * @since 11.0 (generics widened in 13.0) 206 | */ 207 | public static Iterable presentInstances( 208 | final Iterable> optionals) { 209 | checkNotNull(optionals); 210 | return new Iterable() { 211 | @Override 212 | public Iterator iterator() { 213 | return new AbstractIterator() { 214 | private final Iterator> iterator = 215 | checkNotNull(optionals.iterator()); 216 | 217 | @Override 218 | protected T computeNext() { 219 | while (iterator.hasNext()) { 220 | Optional optional = iterator.next(); 221 | if (optional.isPresent()) { 222 | return optional.get(); 223 | } 224 | } 225 | return endOfData(); 226 | } 227 | }; 228 | } 229 | }; 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/strings/Joiner.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2008 The Guava Authors 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 | package com.fernandocejas.arrow.strings; 17 | 18 | import java.io.IOException; 19 | import java.util.AbstractList; 20 | import java.util.Arrays; 21 | import java.util.Iterator; 22 | import java.util.Map; 23 | import org.jetbrains.annotations.Nullable; 24 | 25 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 26 | 27 | /** 28 | * An object which joins pieces of text (specified as an array, {@link Iterable}, varargs or even a 29 | * {@link Map}) with a separator. It either appends the results to an {@link Appendable} or returns 30 | * them as a {@link String}. Example:
   {@code
 31 |  * 

32 | * Joiner joiner = Joiner.on("; ").skipNulls(); 33 | * . . . 34 | * return joiner.join("Harry", null, "Ron", "Hermione");}

35 | *

36 | *

This returns the string {@code "Harry; Ron; Hermione"}. Note that all input elements are 37 | * converted to strings using {@link Object#toString()} before being appended. 38 | *

39 | *

If neither {@link #skipNulls()} nor {@link #useForNull(String)} is specified, the joining 40 | * methods will throw {@link NullPointerException} if any given element is null. 41 | *

42 | *

Warning: joiner instances are always immutable; a configuration method such as {@code 43 | * useForNull} has no effect on the instance it is invoked on! You must store and use the new 44 | * joiner 45 | * instance returned by the method. This makes joiners thread-safe, and safe to store as {@code 46 | * static final} constants.

   {@code
 47 |  * 

48 | * // Bad! Do not do this! 49 | * Joiner joiner = Joiner.on(','); 50 | * joiner.skipNulls(); // does nothing! 51 | * return joiner.join("wrong", null, "wrong");}

52 | *

53 | *

See the Guava User Guide article on {@code Joiner}. 55 | * 56 | *

This class contains code derived from Google 57 | * Guava 58 | * 59 | * @author Kevin Bourrillion 60 | */ 61 | public class Joiner { 62 | 63 | private final String separator; 64 | 65 | Joiner(String separator) { 66 | this.separator = checkNotNull(separator); 67 | } 68 | 69 | private Joiner(Joiner prototype) { 70 | this.separator = prototype.separator; 71 | } 72 | 73 | /** 74 | * Appends the string representation of each of {@code parts}, using the previously configured 75 | * separator between each, to {@code appendable}. 76 | */ 77 | public A appendTo(A appendable, Iterable parts) throws IOException { 78 | return appendTo(appendable, parts.iterator()); 79 | } 80 | 81 | /** 82 | * Appends the string representation of each of {@code parts}, using the previously configured 83 | * separator between each, to {@code appendable}. 84 | * 85 | * @since 11.0 86 | */ 87 | public A appendTo(A appendable, Iterator parts) throws IOException { 88 | checkNotNull(appendable); 89 | if (parts.hasNext()) { 90 | appendable.append(toString(parts.next())); 91 | while (parts.hasNext()) { 92 | appendable.append(separator); 93 | appendable.append(toString(parts.next())); 94 | } 95 | } 96 | return appendable; 97 | } 98 | 99 | /** 100 | * Appends the string representation of each of {@code parts}, using the previously configured 101 | * separator between each, to {@code appendable}. 102 | */ 103 | public final A appendTo(A appendable, Object[] parts) throws IOException { 104 | return appendTo(appendable, Arrays.asList(parts)); 105 | } 106 | 107 | /** 108 | * Appends to {@code appendable} the string representation of each of the remaining arguments. 109 | */ 110 | public final A appendTo( 111 | A appendable, @Nullable Object first, @Nullable Object second, Object... rest) 112 | throws IOException { 113 | return appendTo(appendable, iterable(first, second, rest)); 114 | } 115 | 116 | /** 117 | * Appends the string representation of each of {@code parts}, using the previously configured 118 | * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable, 119 | * Iterable)}, except that it does not throw {@link IOException}. 120 | */ 121 | public final StringBuilder appendTo(StringBuilder builder, Iterable parts) { 122 | return appendTo(builder, parts.iterator()); 123 | } 124 | 125 | /** 126 | * Appends the string representation of each of {@code parts}, using the previously configured 127 | * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable, 128 | * Iterable)}, except that it does not throw {@link IOException}. 129 | * 130 | * @since 11.0 131 | */ 132 | public final StringBuilder appendTo(StringBuilder builder, Iterator parts) { 133 | try { 134 | appendTo((Appendable) builder, parts); 135 | } catch (IOException impossible) { 136 | throw new AssertionError(impossible); 137 | } 138 | return builder; 139 | } 140 | 141 | /** 142 | * Appends the string representation of each of {@code parts}, using the previously configured 143 | * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable, 144 | * Iterable)}, except that it does not throw {@link IOException}. 145 | */ 146 | public final StringBuilder appendTo(StringBuilder builder, Object[] parts) { 147 | return appendTo(builder, Arrays.asList(parts)); 148 | } 149 | 150 | /** 151 | * Appends to {@code builder} the string representation of each of the remaining arguments. 152 | * Identical to {@link #appendTo(Appendable, Object, Object, Object...)}, except that it does not 153 | * throw {@link IOException}. 154 | */ 155 | public final StringBuilder appendTo( 156 | StringBuilder builder, @Nullable Object first, @Nullable Object second, Object... rest) { 157 | return appendTo(builder, iterable(first, second, rest)); 158 | } 159 | 160 | /** 161 | * Returns a string containing the string representation of each of {@code parts}, using the 162 | * previously configured separator between each. 163 | */ 164 | public final String join(Iterable parts) { 165 | return join(parts.iterator()); 166 | } 167 | 168 | /** 169 | * Returns a string containing the string representation of each of {@code parts}, using the 170 | * previously configured separator between each. 171 | * 172 | * @since 11.0 173 | */ 174 | public final String join(Iterator parts) { 175 | return appendTo(new StringBuilder(), parts).toString(); 176 | } 177 | 178 | /** 179 | * Returns a string containing the string representation of each of {@code parts}, using the 180 | * previously configured separator between each. 181 | */ 182 | public final String join(Object[] parts) { 183 | return join(Arrays.asList(parts)); 184 | } 185 | 186 | /** 187 | * Returns a string containing the string representation of each argument, using the previously 188 | * configured separator between each. 189 | */ 190 | public final String join(@Nullable Object first, @Nullable Object second, Object... rest) { 191 | return join(iterable(first, second, rest)); 192 | } 193 | 194 | /** 195 | * Returns a joiner with the same behavior as this one, except automatically substituting {@code 196 | * nullText} for any provided null elements. 197 | */ 198 | public Joiner useForNull(final String nullText) { 199 | checkNotNull(nullText); 200 | return new Joiner(this) { 201 | @Override CharSequence toString(@Nullable Object part) { 202 | return (part == null) ? nullText : Joiner.this.toString(part); 203 | } 204 | 205 | @Override 206 | public Joiner useForNull(String nullText) { 207 | throw new UnsupportedOperationException("already specified useForNull"); 208 | } 209 | 210 | @Override 211 | public Joiner skipNulls() { 212 | throw new UnsupportedOperationException("already specified useForNull"); 213 | } 214 | }; 215 | } 216 | 217 | /** 218 | * Returns a joiner with the same behavior as this joiner, except automatically skipping over any 219 | * provided null elements. 220 | */ 221 | public Joiner skipNulls() { 222 | return new Joiner(this) { 223 | @Override 224 | public A appendTo(A appendable, Iterator parts) 225 | throws IOException { 226 | checkNotNull(appendable, "appendable"); 227 | checkNotNull(parts, "parts"); 228 | while (parts.hasNext()) { 229 | Object part = parts.next(); 230 | if (part != null) { 231 | appendable.append(Joiner.this.toString(part)); 232 | break; 233 | } 234 | } 235 | while (parts.hasNext()) { 236 | Object part = parts.next(); 237 | if (part != null) { 238 | appendable.append(separator); 239 | appendable.append(Joiner.this.toString(part)); 240 | } 241 | } 242 | return appendable; 243 | } 244 | 245 | @Override 246 | public Joiner useForNull(String nullText) { 247 | throw new UnsupportedOperationException("already specified skipNulls"); 248 | } 249 | }; 250 | } 251 | 252 | CharSequence toString(Object part) { 253 | checkNotNull(part); // checkNotNull for GWT (do not optimize). 254 | return part instanceof CharSequence ? (CharSequence) part : part.toString(); 255 | } 256 | 257 | private static Iterable iterable( 258 | final Object first, final Object second, final Object[] rest) { 259 | checkNotNull(rest); 260 | return new AbstractList() { 261 | @Override 262 | public int size() { 263 | return rest.length + 2; 264 | } 265 | 266 | @Override 267 | public Object get(int index) { 268 | switch (index) { 269 | case 0: 270 | return first; 271 | case 1: 272 | return second; 273 | default: 274 | return rest[index - 2]; 275 | } 276 | } 277 | }; 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/checks/Preconditions.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.fernandocejas.arrow.checks; 15 | 16 | import org.jetbrains.annotations.Nullable; 17 | 18 | /** 19 | * Static convenience methods that help a method or constructor check whether it was invoked 20 | * correctly (whether its preconditions have been met). These methods generally accept a 21 | * {@code boolean} expression which is expected to be {@code true} (or in the case of {@code 22 | * checkNotNull}, an object reference which is expected to be non-null). When {@code false} (or 23 | * {@code null}) is passed instead, the {@code Preconditions} method throws an unchecked exception, 24 | * which helps the calling method communicate to its caller that that caller has made 25 | * a mistake. Example:
   {@code
 26 |  * 

27 | * /** 28 | * * Returns the positive square root of the given value. 29 | * * 30 | * * @throws IllegalArgumentException if the value is negative 31 | * *}{@code / 32 | * public static double sqrt(double value) { 33 | * Preconditions.checkArgument(value >= 0.0, "negative value: %s", value); 34 | * // calculate the square root 35 | * } 36 | *

37 | * void exampleBadCaller() { 38 | * double d = sqrt(-1.0); 39 | * }}

40 | *

41 | * In this example, {@code checkArgument} throws an {@code IllegalArgumentException} to indicate 42 | * that {@code exampleBadCaller} made an error in its call to {@code sqrt}. 43 | *

44 | *

Warning about performance

45 | *

46 | *

The goal of this class is to improve readability of code, but in some circumstances this may 47 | * come at a significant performance cost. Remember that parameter values for message construction 48 | * must all be computed eagerly, and autoboxing and varargs array creation may happen as well, even 49 | * when the precondition check then succeeds (as it should almost always do in production). In some 50 | * circumstances these wasted CPU cycles and allocations can add up to a real problem. 51 | * Performance-sensitive precondition checks can always be converted to the customary form: 52 | *

   {@code
 53 |  * 

54 | * if (value < 0.0) { 55 | * throw new IllegalArgumentException("negative value: " + value); 56 | * }}

57 | *

58 | *

Other types of preconditions

59 | *

60 | *

Not every type of precondition failure is supported by these methods. Continue to throw 61 | * standard JDK exceptions such as {@link java.util.NoSuchElementException} or {@link 62 | * UnsupportedOperationException} in the situations they are intended for. 63 | *

64 | *

Non-preconditions

65 | *

66 | *

It is of course possible to use the methods of this class to check for invalid conditions 67 | * which are not the caller's fault. Doing so is not recommended because it is 68 | * misleading to future readers of the code and of stack traces. See 69 | * Conditional 70 | * failures explained in the Guava User Guide for more advice. 71 | *

72 | *

{@code java.util.Objects.requireNonNull()}

73 | *

74 | *

Only {@code %s} is supported

75 | *

76 | *

In {@code Preconditions} error message template strings, only the {@code "%s"} specifier is 77 | * supported, not the full range of {@link java.util.Formatter} specifiers. 78 | *

79 | *

More information

80 | *

81 | *

See the Guava User Guide on 82 | * using {@code 83 | * Preconditions}. 84 | *

85 | *

This class contains code derived from Google 86 | * Guava 87 | * 88 | * @author Kevin Bourrillion 89 | */ 90 | public final class Preconditions { 91 | private Preconditions() { 92 | } 93 | 94 | /** 95 | * Ensures the truth of an expression involving one or more parameters to the calling method. 96 | * 97 | * @param expression a boolean expression 98 | * @throws IllegalArgumentException if {@code expression} is false 99 | */ 100 | public static void checkArgument(boolean expression) { 101 | if (!expression) { 102 | throw new IllegalArgumentException(); 103 | } 104 | } 105 | 106 | /** 107 | * Ensures the truth of an expression involving one or more parameters to the calling method. 108 | * 109 | * @param expression a boolean expression 110 | * @param errorMessage the exception message to use if the check fails; will be converted to a 111 | * string using {@link String#valueOf(Object)} 112 | * @throws IllegalArgumentException if {@code expression} is false 113 | */ 114 | public static void checkArgument(boolean expression, @Nullable Object errorMessage) { 115 | if (!expression) { 116 | throw new IllegalArgumentException(String.valueOf(errorMessage)); 117 | } 118 | } 119 | 120 | /** 121 | * Ensures the truth of an expression involving the state of the calling instance, but not 122 | * involving any parameters to the calling method. 123 | * 124 | * @param expression a boolean expression 125 | * @throws IllegalStateException if {@code expression} is false 126 | */ 127 | public static void checkState(boolean expression) { 128 | if (!expression) { 129 | throw new IllegalStateException(); 130 | } 131 | } 132 | 133 | /** 134 | * Ensures the truth of an expression involving the state of the calling instance, but not 135 | * involving any parameters to the calling method. 136 | * 137 | * @param expression a boolean expression 138 | * @param errorMessage the exception message to use if the check fails; will be converted to a 139 | * string using {@link String#valueOf(Object)} 140 | * @throws IllegalStateException if {@code expression} is false 141 | */ 142 | public static void checkState(boolean expression, @Nullable Object errorMessage) { 143 | if (!expression) { 144 | throw new IllegalStateException(String.valueOf(errorMessage)); 145 | } 146 | } 147 | 148 | /** 149 | * Ensures that an object reference passed as a parameter to the calling method is not null. 150 | * 151 | * @param reference an object reference 152 | * @return the non-null reference that was validated 153 | * @throws NullPointerException if {@code reference} is null 154 | */ 155 | public static T checkNotNull(T reference) { 156 | if (reference == null) { 157 | throw new NullPointerException(); 158 | } 159 | return reference; 160 | } 161 | 162 | /** 163 | * Ensures that an object reference passed as a parameter to the calling method is not null. 164 | * 165 | * @param reference an object reference 166 | * @param errorMessage the exception message to use if the check fails; will be converted to a 167 | * string using {@link String#valueOf(Object)} 168 | * @return the non-null reference that was validated 169 | * @throws NullPointerException if {@code reference} is null 170 | */ 171 | public static T checkNotNull(T reference, @Nullable Object errorMessage) { 172 | if (reference == null) { 173 | throw new NullPointerException(String.valueOf(errorMessage)); 174 | } 175 | return reference; 176 | } 177 | 178 | /** 179 | * Ensures that {@code index} specifies a valid element in an array, list or string of 180 | * size 181 | * {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive. 182 | * 183 | * @param index a user-supplied index identifying an element of an array, list or string 184 | * @param size the size of that array, list or string 185 | * @return the value of {@code index} 186 | * @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code 187 | * size} 188 | * @throws IllegalArgumentException if {@code size} is negative 189 | */ 190 | public static int checkElementIndex(int index, int size) { 191 | return checkElementIndex(index, size, "index"); 192 | } 193 | 194 | /** 195 | * Ensures that {@code index} specifies a valid element in an array, list or string of 196 | * size 197 | * {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive. 198 | * 199 | * @param index a user-supplied index identifying an element of an array, list or string 200 | * @param size the size of that array, list or string 201 | * @param desc the text to use to describe this index in an error message 202 | * @return the value of {@code index} 203 | * @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code 204 | * size} 205 | * @throws IllegalArgumentException if {@code size} is negative 206 | */ 207 | public static int checkElementIndex( 208 | int index, int size, @Nullable String desc) { 209 | // Carefully optimized for execution by hotspot (explanatory comment above) 210 | if (index < 0 || index >= size) { 211 | throw new IndexOutOfBoundsException(badElementIndex(index, size, desc)); 212 | } 213 | return index; 214 | } 215 | 216 | private static String badElementIndex(int index, int size, String desc) { 217 | if (index < 0) { 218 | return format("%s (%s) must not be negative", desc, index); 219 | } else if (size < 0) { 220 | throw new IllegalArgumentException("negative size: " + size); 221 | } else { // index >= size 222 | return format("%s (%s) must be less than size (%s)", desc, index, size); 223 | } 224 | } 225 | 226 | /** 227 | * Ensures that {@code index} specifies a valid position in an array, list or string of 228 | * size {@code size}. A position index may range from zero to {@code size}, inclusive. 229 | * 230 | * @param index a user-supplied index identifying a position in an array, list or string 231 | * @param size the size of that array, list or string 232 | * @return the value of {@code index} 233 | * @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size} 234 | * @throws IllegalArgumentException if {@code size} is negative 235 | */ 236 | public static int checkPositionIndex(int index, int size) { 237 | return checkPositionIndex(index, size, "index"); 238 | } 239 | 240 | /** 241 | * Ensures that {@code index} specifies a valid position in an array, list or string of 242 | * size {@code size}. A position index may range from zero to {@code size}, inclusive. 243 | * 244 | * @param index a user-supplied index identifying a position in an array, list or string 245 | * @param size the size of that array, list or string 246 | * @param desc the text to use to describe this index in an error message 247 | * @return the value of {@code index} 248 | * @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size} 249 | * @throws IllegalArgumentException if {@code size} is negative 250 | */ 251 | public static int checkPositionIndex(int index, int size, @Nullable String desc) { 252 | // Carefully optimized for execution by hotspot (explanatory comment above) 253 | if (index < 0 || index > size) { 254 | throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); 255 | } 256 | return index; 257 | } 258 | 259 | private static String badPositionIndex(int index, int size, String desc) { 260 | if (index < 0) { 261 | return format("%s (%s) must not be negative", desc, index); 262 | } else if (size < 0) { 263 | throw new IllegalArgumentException("negative size: " + size); 264 | } else { // index > size 265 | return format("%s (%s) must not be greater than size (%s)", desc, index, size); 266 | } 267 | } 268 | 269 | /** 270 | * Ensures that {@code start} and {@code end} specify a valid positions in an array, list 271 | * or string of size {@code size}, and are in order. A position index may range from zero to 272 | * {@code size}, inclusive. 273 | * 274 | * @param start a user-supplied index identifying a starting position in an array, list or string 275 | * @param end a user-supplied index identifying a ending position in an array, list or string 276 | * @param size the size of that array, list or string 277 | * @throws IndexOutOfBoundsException if either index is negative or is greater than {@code size}, 278 | * or if {@code end} is less than {@code start} 279 | * @throws IllegalArgumentException if {@code size} is negative 280 | */ 281 | public static void checkPositionIndexes(int start, int end, int size) { 282 | // Carefully optimized for execution by hotspot (explanatory comment above) 283 | if (start < 0 || end < start || end > size) { 284 | throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); 285 | } 286 | } 287 | 288 | private static String badPositionIndexes(int start, int end, int size) { 289 | if (start < 0 || start > size) { 290 | return badPositionIndex(start, size, "start index"); 291 | } 292 | if (end < 0 || end > size) { 293 | return badPositionIndex(end, size, "end index"); 294 | } 295 | // end < start 296 | return format("end index (%s) must not be less than start index (%s)", end, start); 297 | } 298 | 299 | /** 300 | * Substitutes each {@code %s} in {@code template} with an argument. These are matched by 301 | * position: the first {@code %s} gets {@code args[0]}, etc. If there are more arguments than 302 | * placeholders, the unmatched arguments will be appended to the end of the formatted message in 303 | * square braces. 304 | * 305 | * @param template a non-null string containing 0 or more {@code %s} placeholders. 306 | * @param args the arguments to be substituted into the message template. Arguments are converted 307 | * to strings using {@link String#valueOf(Object)}. Arguments can be null. 308 | */ 309 | // Note that this is somewhat-improperly used from Verify.java as well. 310 | static String format(String template, Object... args) { 311 | String normTemplate = String.valueOf(template); // null -> "null" 312 | 313 | // start substituting the arguments into the '%s' placeholders 314 | StringBuilder builder = new StringBuilder(normTemplate.length() + 16 * args.length); 315 | int templateStart = 0; 316 | int i = 0; 317 | while (i < args.length) { 318 | int placeholderStart = normTemplate.indexOf("%s", templateStart); 319 | if (placeholderStart == -1) { 320 | break; 321 | } 322 | builder.append(normTemplate.substring(templateStart, placeholderStart)); 323 | builder.append(args[i++]); 324 | templateStart = placeholderStart + 2; 325 | } 326 | builder.append(normTemplate.substring(templateStart)); 327 | 328 | // if we run out of placeholders, append the extra args in square braces 329 | if (i < args.length) { 330 | builder.append(" ["); 331 | builder.append(args[i++]); 332 | while (i < args.length) { 333 | builder.append(", "); 334 | builder.append(args[i++]); 335 | } 336 | builder.append(']'); 337 | } 338 | 339 | return builder.toString(); 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/objects/MoreObjects.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 The Guava Authors 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 | package com.fernandocejas.arrow.objects; 17 | 18 | import com.fernandocejas.arrow.optional.Optional; 19 | import java.util.Arrays; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 23 | 24 | /** 25 | * Helper functions that operate on any {@code Object}, and are not already provided in 26 | * {@link java.util.Objects}. 27 | * 28 | *

See the Guava User Guide on writing 30 | * {@code Object} methods with {@code Objects}. 31 | * 32 | * @author Laurence Gonsalves 33 | * @since 18.0 (since 2.0 as {@code Objects}) 34 | * 35 | *

This class contains code derived from Google 36 | * Guava 37 | */ 38 | public final class MoreObjects { 39 | 40 | /** 41 | * Determines whether two possibly-null objects are equal. Returns: 42 | * 43 | *

    44 | *
  • {@code true} if {@code a} and {@code b} are both null. 45 | *
  • {@code true} if {@code a} and {@code b} are both non-null and they are 46 | * equal according to {@link Object#equals(Object)}. 47 | *
  • {@code false} in all other situations. 48 | *
49 | * 50 | *

This assumes that any non-null objects passed to this function conform 51 | * to the {@code equals()} contract. 52 | * 53 | *

Note for Java 7 and later: This method should be treated as 54 | * deprecated; use {@link java.util.Objects#equals} instead. 55 | */ 56 | public static boolean equal(@Nullable Object a, @Nullable Object b) { 57 | return a == b || a != null && a.equals(b); 58 | } 59 | 60 | /** 61 | * Generates a hash code for multiple values. The hash code is generated by 62 | * calling {@link Arrays#hashCode(Object[])}. Note that array arguments to 63 | * this method, with the exception of a single Object array, do not get any 64 | * special handling; their hash codes are based on identity and not contents. 65 | * 66 | *

This is useful for implementing {@link Object#hashCode()}. For example, 67 | * in an object that has three properties, {@code x}, {@code y}, and 68 | * {@code z}, one could write: 69 | *

   {@code
 70 |    *   public int hashCode() {
 71 |    *     return Objects.hashCode(getX(), getY(), getZ());
 72 |    *   }}
73 | * 74 | *

Warning: When a single object is supplied, the returned hash code 75 | * does not equal the hash code of that object. 76 | * 77 | *

Note for Java 7 and later: This method should be treated as 78 | * deprecated; use {@link java.util.Objects#hash} instead. 79 | */ 80 | public static int hashCode(@Nullable Object... objects) { 81 | return Arrays.hashCode(objects); 82 | } 83 | 84 | /** 85 | * Returns the first of two given parameters that is not {@code null}, if either is, or otherwise 86 | * throws a {@link NullPointerException}. 87 | * 88 | *

Note: if {@code first} is represented as an {@link Optional}, this can be 89 | * accomplished with {@link Optional#or(Object) first.or(second)}. 90 | * 91 | * @return {@code first} if it is non-null; otherwise {@code second} if it is non-null 92 | * @throws NullPointerException if both {@code first} and {@code second} are null 93 | * @since 18.0 (since 3.0 as {@code Objects.firstNonNull()}. 94 | */ 95 | public static T firstNonNull(@Nullable T first, @Nullable T second) { 96 | return first != null ? first : checkNotNull(second); 97 | } 98 | 99 | /** 100 | * Creates an instance of {@link ToStringHelper}. 101 | * 102 | *

This is helpful for implementing {@link Object#toString()}. 103 | * Specification by example:

   {@code
104 |    *   // Returns "ClassName{}"
105 |    *   MoreObjects.toStringHelper(this)
106 |    *       .toString();
107 |    *
108 |    *   // Returns "ClassName{x=1}"
109 |    *   MoreObjects.toStringHelper(this)
110 |    *       .add("x", 1)
111 |    *       .toString();
112 |    *
113 |    *   // Returns "MyObject{x=1}"
114 |    *   MoreObjects.toStringHelper("MyObject")
115 |    *       .add("x", 1)
116 |    *       .toString();
117 |    *
118 |    *   // Returns "ClassName{x=1, y=foo}"
119 |    *   MoreObjects.toStringHelper(this)
120 |    *       .add("x", 1)
121 |    *       .add("y", "foo")
122 |    *       .toString();
123 |    *
124 |    *   // Returns "ClassName{x=1}"
125 |    *   MoreObjects.toStringHelper(this)
126 |    *       .omitNullValues()
127 |    *       .add("x", 1)
128 |    *       .add("y", null)
129 |    *       .toString();
130 |    *   }}
131 | * 132 | *

Note that in GWT, class names are often obfuscated. 133 | * 134 | * @param self the object to generate the string for (typically {@code this}), used only for its 135 | * class name 136 | * @since 18.0 (since 2.0 as {@code Objects.toStringHelper()}. 137 | */ 138 | public static ToStringHelper toStringHelper(Object self) { 139 | return new ToStringHelper(simpleName(self.getClass())); 140 | } 141 | 142 | /** 143 | * Creates an instance of {@link ToStringHelper} in the same manner as {@link 144 | * #toStringHelper(Object)}, but using the simple name of {@code clazz} instead of using an 145 | * instance's {@link Object#getClass()}. 146 | * 147 | *

Note that in GWT, class names are often obfuscated. 148 | * 149 | * @param clazz the {@link Class} of the instance 150 | * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}. 151 | */ 152 | public static ToStringHelper toStringHelper(Class clazz) { 153 | return new ToStringHelper(simpleName(clazz)); 154 | } 155 | 156 | /** 157 | * Creates an instance of {@link ToStringHelper} in the same manner as {@link 158 | * #toStringHelper(Object)}, but using {@code className} instead of using an instance's {@link 159 | * Object#getClass()}. 160 | * 161 | * @param className the name of the instance type 162 | * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}. 163 | */ 164 | public static ToStringHelper toStringHelper(String className) { 165 | return new ToStringHelper(className); 166 | } 167 | 168 | /** 169 | * {@link Class#getSimpleName()} is not GWT compatible yet, so we 170 | * provide our own implementation. 171 | */ 172 | // Package-private so Objects can call it. 173 | static String simpleName(Class clazz) { 174 | String name = clazz.getName(); 175 | 176 | // the nth anonymous class has a class name ending in "Outer$n" 177 | // and local inner classes have names ending in "Outer.$1Inner" 178 | name = name.replaceAll("\\$[0-9]+", "\\$"); 179 | 180 | // we want the name of the inner class all by its lonesome 181 | int start = name.lastIndexOf('$'); 182 | 183 | // if this isn't an inner class, just find the start of the 184 | // top level class name. 185 | if (start == -1) { 186 | start = name.lastIndexOf('.'); 187 | } 188 | return name.substring(start + 1); 189 | } 190 | 191 | /** 192 | * Support class for {@link MoreObjects#toStringHelper}. 193 | * 194 | * @author Jason Lee 195 | * @since 18.0 (since 2.0 as {@code Objects.ToStringHelper}. 196 | */ 197 | public static final class ToStringHelper { 198 | private final String className; 199 | private final ValueHolder holderHead = new ValueHolder(); 200 | private ValueHolder holderTail = holderHead; 201 | private boolean omitNullValues; 202 | 203 | /** 204 | * Use {@link MoreObjects#toStringHelper(Object)} to create an instance. 205 | */ 206 | ToStringHelper(String className) { 207 | this.className = checkNotNull(className); 208 | } 209 | 210 | /** 211 | * Configures the {@link ToStringHelper} so {@link #toString()} will ignore 212 | * properties with null value. The order of calling this method, relative 213 | * to the {@code add()}/{@code addValue()} methods, is not significant. 214 | * 215 | * @since 18.0 (since 12.0 as {@code Objects.ToStringHelper.omitNullValues()}. 216 | */ 217 | public ToStringHelper omitNullValues() { 218 | omitNullValues = true; 219 | return this; 220 | } 221 | 222 | /** 223 | * Adds a name/value pair to the formatted output in {@code name=value} 224 | * format. If {@code value} is {@code null}, the string {@code "null"} 225 | * is used, unless {@link #omitNullValues()} is called, in which case this 226 | * name/value pair will not be added. 227 | */ 228 | public ToStringHelper add(String name, @Nullable Object value) { 229 | return addHolder(name, value); 230 | } 231 | 232 | /** 233 | * Adds a name/value pair to the formatted output in {@code name=value} 234 | * format. 235 | * 236 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 237 | */ 238 | public ToStringHelper add(String name, boolean value) { 239 | return addHolder(name, String.valueOf(value)); 240 | } 241 | 242 | /** 243 | * Adds a name/value pair to the formatted output in {@code name=value} 244 | * format. 245 | * 246 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 247 | */ 248 | public ToStringHelper add(String name, char value) { 249 | return addHolder(name, String.valueOf(value)); 250 | } 251 | 252 | /** 253 | * Adds a name/value pair to the formatted output in {@code name=value} 254 | * format. 255 | * 256 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 257 | */ 258 | public ToStringHelper add(String name, double value) { 259 | return addHolder(name, String.valueOf(value)); 260 | } 261 | 262 | /** 263 | * Adds a name/value pair to the formatted output in {@code name=value} 264 | * format. 265 | * 266 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 267 | */ 268 | public ToStringHelper add(String name, float value) { 269 | return addHolder(name, String.valueOf(value)); 270 | } 271 | 272 | /** 273 | * Adds a name/value pair to the formatted output in {@code name=value} 274 | * format. 275 | * 276 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 277 | */ 278 | public ToStringHelper add(String name, int value) { 279 | return addHolder(name, String.valueOf(value)); 280 | } 281 | 282 | /** 283 | * Adds a name/value pair to the formatted output in {@code name=value} 284 | * format. 285 | * 286 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 287 | */ 288 | public ToStringHelper add(String name, long value) { 289 | return addHolder(name, String.valueOf(value)); 290 | } 291 | 292 | /** 293 | * Adds an unnamed value to the formatted output. 294 | * 295 | *

It is strongly encouraged to use {@link #add(String, Object)} instead 296 | * and give value a readable name. 297 | * 298 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 299 | */ 300 | public ToStringHelper addValue(@Nullable Object value) { 301 | return addHolder(value); 302 | } 303 | 304 | /** 305 | * Adds an unnamed value to the formatted output. 306 | * 307 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 308 | */ 309 | public ToStringHelper addValue(boolean value) { 310 | return addHolder(String.valueOf(value)); 311 | } 312 | 313 | /** 314 | * Adds an unnamed value to the formatted output. 315 | * 316 | *

It is strongly encouraged to use {@link #add(String, char)} instead 317 | * and give value a readable name. 318 | * 319 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 320 | */ 321 | public ToStringHelper addValue(char value) { 322 | return addHolder(String.valueOf(value)); 323 | } 324 | 325 | /** 326 | * Adds an unnamed value to the formatted output. 327 | * 328 | *

It is strongly encouraged to use {@link #add(String, double)} instead 329 | * and give value a readable name. 330 | * 331 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 332 | */ 333 | public ToStringHelper addValue(double value) { 334 | return addHolder(String.valueOf(value)); 335 | } 336 | 337 | /** 338 | * Adds an unnamed value to the formatted output. 339 | * 340 | *

It is strongly encouraged to use {@link #add(String, float)} instead 341 | * and give value a readable name. 342 | * 343 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 344 | */ 345 | public ToStringHelper addValue(float value) { 346 | return addHolder(String.valueOf(value)); 347 | } 348 | 349 | /** 350 | * Adds an unnamed value to the formatted output. 351 | * 352 | *

It is strongly encouraged to use {@link #add(String, int)} instead 353 | * and give value a readable name. 354 | * 355 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 356 | */ 357 | public ToStringHelper addValue(int value) { 358 | return addHolder(String.valueOf(value)); 359 | } 360 | 361 | /** 362 | * Adds an unnamed value to the formatted output. 363 | * 364 | *

It is strongly encouraged to use {@link #add(String, long)} instead 365 | * and give value a readable name. 366 | * 367 | * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.omitNullValues()}. 368 | */ 369 | public ToStringHelper addValue(long value) { 370 | return addHolder(String.valueOf(value)); 371 | } 372 | 373 | /** 374 | * Returns a string in the format specified by 375 | * {@link MoreObjects#toStringHelper(Object)}. 376 | * 377 | *

After calling this method, you can keep adding more properties to later 378 | * call toString() again and get a more complete representation of the 379 | * same object; but properties cannot be removed, so this only allows 380 | * limited reuse of the helper instance. The helper allows duplication of 381 | * properties (multiple name/value pairs with the same name can be added). 382 | */ 383 | @Override 384 | public String toString() { 385 | // create a copy to keep it consistent in case value changes 386 | boolean omitNullValuesSnapshot = omitNullValues; 387 | String nextSeparator = ""; 388 | StringBuilder builder = new StringBuilder(32).append(className) 389 | .append('{'); 390 | for (ValueHolder valueHolder = holderHead.next; valueHolder != null; 391 | valueHolder = valueHolder.next) { 392 | if (!omitNullValuesSnapshot || valueHolder.value != null) { 393 | builder.append(nextSeparator); 394 | nextSeparator = ", "; 395 | 396 | if (valueHolder.name != null) { 397 | builder.append(valueHolder.name).append('='); 398 | } 399 | builder.append(valueHolder.value); 400 | } 401 | } 402 | return builder.append('}').toString(); 403 | } 404 | 405 | private ValueHolder addHolder() { 406 | ValueHolder valueHolder = new ValueHolder(); 407 | holderTail = holderTail.next = valueHolder; 408 | return valueHolder; 409 | } 410 | 411 | private ToStringHelper addHolder(@Nullable Object value) { 412 | ValueHolder valueHolder = addHolder(); 413 | valueHolder.value = value; 414 | return this; 415 | } 416 | 417 | private ToStringHelper addHolder(String name, @Nullable Object value) { 418 | ValueHolder valueHolder = addHolder(); 419 | valueHolder.value = value; 420 | valueHolder.name = checkNotNull(name); 421 | return this; 422 | } 423 | 424 | private static final class ValueHolder { 425 | String name; 426 | Object value; 427 | ValueHolder next; 428 | } 429 | } 430 | 431 | private MoreObjects() { 432 | // no instances 433 | } 434 | } 435 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/Iterators.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import com.fernandocejas.arrow.checks.Preconditions; 19 | import com.fernandocejas.arrow.functions.Predicate; 20 | import com.fernandocejas.arrow.functions.Predicates; 21 | import com.fernandocejas.arrow.objects.MoreObjects; 22 | import com.fernandocejas.arrow.optional.Optional; 23 | import java.util.Arrays; 24 | import java.util.Collection; 25 | import java.util.Collections; 26 | import java.util.Iterator; 27 | import java.util.List; 28 | import java.util.NoSuchElementException; 29 | import org.jetbrains.annotations.Nullable; 30 | 31 | /** 32 | * This class contains static utility methods that operate on or return objects 33 | * of type {@link Iterator}. Except as noted, each method has a corresponding 34 | * {@link Iterable}-based method in the {@link Iterables} class. 35 | * 36 | *

Performance notes: Unless otherwise noted, all of the iterators 37 | * produced in this class are lazy, which means that they only advance 38 | * the backing iteration when absolutely necessary. 39 | * 40 | *

See the Guava User Guide section on 42 | * {@code Iterators}. 43 | * 44 | * @author Kevin Bourrillion 45 | * @author Jared Levy 46 | * @since 2.0 (imported from Google Collections Library) 47 | */ 48 | public final class Iterators { 49 | private Iterators() { 50 | } 51 | 52 | /** 53 | * Returns the number of elements remaining in {@code iterator}. The iterator 54 | * will be left exhausted: its {@code hasNext()} method will return 55 | * {@code false}. 56 | */ 57 | public static int size(Iterator iterator) { 58 | int count = 0; 59 | while (iterator.hasNext()) { 60 | iterator.next(); 61 | count++; 62 | } 63 | return count; 64 | } 65 | 66 | /** 67 | * Returns {@code true} if {@code iterator} contains {@code element}. 68 | */ 69 | public static boolean contains(Iterator iterator, @Nullable Object element) { 70 | return any(iterator, Predicates.equalTo(element)); 71 | } 72 | 73 | /** 74 | * Traverses an iterator and removes every element that belongs to the 75 | * provided collection. The iterator will be left exhausted: its 76 | * {@code hasNext()} method will return {@code false}. 77 | * 78 | * @param removeFrom the iterator to (potentially) remove elements from 79 | * @param elementsToRemove the elements to remove 80 | * @return {@code true} if any element was removed from {@code iterator} 81 | */ 82 | public static boolean removeAll( 83 | Iterator removeFrom, Collection elementsToRemove) { 84 | return removeIf(removeFrom, Predicates.in(elementsToRemove)); 85 | } 86 | 87 | /** 88 | * Removes every element that satisfies the provided predicate from the 89 | * iterator. The iterator will be left exhausted: its {@code hasNext()} 90 | * method will return {@code false}. 91 | * 92 | * @param removeFrom the iterator to (potentially) remove elements from 93 | * @param predicate a predicate that determines whether an element should 94 | * be removed 95 | * @return {@code true} if any elements were removed from the iterator 96 | * @since 2.0 97 | */ 98 | public static boolean removeIf( 99 | Iterator removeFrom, Predicate predicate) { 100 | Preconditions.checkNotNull(predicate); 101 | boolean modified = false; 102 | while (removeFrom.hasNext()) { 103 | if (predicate.apply(removeFrom.next())) { 104 | removeFrom.remove(); 105 | modified = true; 106 | } 107 | } 108 | return modified; 109 | } 110 | 111 | /** 112 | * Traverses an iterator and removes every element that does not belong to the 113 | * provided collection. The iterator will be left exhausted: its 114 | * {@code hasNext()} method will return {@code false}. 115 | * 116 | * @param removeFrom the iterator to (potentially) remove elements from 117 | * @param elementsToRetain the elements to retain 118 | * @return {@code true} if any element was removed from {@code iterator} 119 | */ 120 | public static boolean retainAll( 121 | Iterator removeFrom, Collection elementsToRetain) { 122 | return removeIf(removeFrom, Predicates.not(Predicates.in(elementsToRetain))); 123 | } 124 | 125 | /** 126 | * Determines whether two iterators contain equal elements in the same order. 127 | * More specifically, this method returns {@code true} if {@code iterator1} 128 | * and {@code iterator2} contain the same number of elements and every element 129 | * of {@code iterator1} is equal to the corresponding element of 130 | * {@code iterator2}. 131 | * 132 | *

Note that this will modify the supplied iterators, since they will have 133 | * been advanced some number of elements forward. 134 | */ 135 | public static boolean elementsEqual( 136 | Iterator iterator1, Iterator iterator2) { 137 | while (iterator1.hasNext()) { 138 | if (!iterator2.hasNext()) { 139 | return false; 140 | } 141 | Object o1 = iterator1.next(); 142 | Object o2 = iterator2.next(); 143 | if (!MoreObjects.equal(o1, o2)) { 144 | return false; 145 | } 146 | } 147 | return !iterator2.hasNext(); 148 | } 149 | 150 | /** 151 | * Returns a string representation of {@code iterator}, with the format 152 | * {@code [e1, e2, ..., en]}. The iterator will be left exhausted: its 153 | * {@code hasNext()} method will return {@code false}. 154 | */ 155 | public static String toString(Iterator iterator) { 156 | return MoreCollections.STANDARD_JOINER 157 | .appendTo(new StringBuilder().append('['), iterator) 158 | .append(']') 159 | .toString(); 160 | } 161 | 162 | /** 163 | * Returns the single element contained in {@code iterator}. 164 | * 165 | * @throws NoSuchElementException if the iterator is empty 166 | * @throws IllegalArgumentException if the iterator contains multiple 167 | * elements. The state of the iterator is unspecified. 168 | */ 169 | public static T getOnlyElement(Iterator iterator) { 170 | T first = iterator.next(); 171 | if (!iterator.hasNext()) { 172 | return first; 173 | } 174 | 175 | throw new IllegalArgumentException("expected one element but found multiple"); 176 | } 177 | 178 | /** 179 | * Returns the single element contained in {@code iterator}, or {@code 180 | * defaultValue} if the iterator is empty. 181 | * 182 | * @throws IllegalArgumentException if the iterator contains multiple 183 | * elements. The state of the iterator is unspecified. 184 | */ 185 | @Nullable 186 | public static T getOnlyElement(Iterator iterator, @Nullable T defaultValue) { 187 | return iterator.hasNext() ? getOnlyElement(iterator) : defaultValue; 188 | } 189 | 190 | /** 191 | * Adds all elements in {@code iterator} to {@code collection}. The iterator 192 | * will be left exhausted: its {@code hasNext()} method will return 193 | * {@code false}. 194 | * 195 | * @return {@code true} if {@code collection} was modified as a result of this 196 | * operation 197 | */ 198 | public static boolean addAll(Collection addTo, Iterator iterator) { 199 | Preconditions.checkNotNull(addTo); 200 | Preconditions.checkNotNull(iterator); 201 | boolean wasModified = false; 202 | while (iterator.hasNext()) { 203 | wasModified |= addTo.add(iterator.next()); 204 | } 205 | return wasModified; 206 | } 207 | 208 | /** 209 | * Divides an iterator into unmodifiable sublists of the given size (the final 210 | * list may be smaller). For example, partitioning an iterator containing 211 | * {@code [a, b, c, d, e]} with a partition size of 3 yields {@code 212 | * [[a, b, c], [d, e]]} -- an outer iterator containing two inner lists of 213 | * three and two elements, all in the original order. 214 | * 215 | *

The returned lists implement {@link java.util.RandomAccess}. 216 | * 217 | * @param iterator the iterator to return a partitioned view of 218 | * @param size the desired size of each partition (the last may be smaller) 219 | * @return an iterator of immutable lists containing the elements of {@code 220 | * iterator} divided into partitions 221 | * @throws IllegalArgumentException if {@code size} is nonpositive 222 | */ 223 | public static UnmodifiableIterator> partition(Iterator iterator, int size) { 224 | return partitionImpl(iterator, size, false); 225 | } 226 | 227 | /** 228 | * Divides an iterator into unmodifiable sublists of the given size, padding 229 | * the final iterator with null values if necessary. For example, partitioning 230 | * an iterator containing {@code [a, b, c, d, e]} with a partition size of 3 231 | * yields {@code [[a, b, c], [d, e, null]]} -- an outer iterator containing 232 | * two inner lists of three elements each, all in the original order. 233 | * 234 | *

The returned lists implement {@link java.util.RandomAccess}. 235 | * 236 | * @param iterator the iterator to return a partitioned view of 237 | * @param size the desired size of each partition 238 | * @return an iterator of immutable lists containing the elements of {@code 239 | * iterator} divided into partitions (the final iterable may have 240 | * trailing null elements) 241 | * @throws IllegalArgumentException if {@code size} is nonpositive 242 | */ 243 | public static UnmodifiableIterator> paddedPartition(Iterator iterator, int size) { 244 | return partitionImpl(iterator, size, true); 245 | } 246 | 247 | private static UnmodifiableIterator> partitionImpl( 248 | final Iterator iterator, final int size, final boolean pad) { 249 | Preconditions.checkNotNull(iterator); 250 | Preconditions.checkArgument(size > 0); 251 | return new UnmodifiableIterator>() { 252 | @Override 253 | public boolean hasNext() { 254 | return iterator.hasNext(); 255 | } 256 | 257 | @Override 258 | public List next() { 259 | if (!hasNext()) { 260 | throw new NoSuchElementException(); 261 | } 262 | Object[] array = new Object[size]; 263 | int count = 0; 264 | for (; count < size && iterator.hasNext(); count++) { 265 | array[count] = iterator.next(); 266 | } 267 | for (int i = count; i < size; i++) { 268 | array[i] = null; // for GWT 269 | } 270 | 271 | @SuppressWarnings("unchecked") // we only put Ts in it 272 | List list = Collections.unmodifiableList( 273 | (List) Arrays.asList(array)); 274 | return pad || count == size ? list : list.subList(0, count); 275 | } 276 | }; 277 | } 278 | 279 | /** 280 | * Returns the elements of {@code unfiltered} that satisfy a predicate. 281 | */ 282 | public static UnmodifiableIterator filter( 283 | final Iterator unfiltered, final Predicate predicate) { 284 | Preconditions.checkNotNull(unfiltered); 285 | Preconditions.checkNotNull(predicate); 286 | return new AbstractIterator() { 287 | @Override 288 | protected T computeNext() { 289 | while (unfiltered.hasNext()) { 290 | T element = unfiltered.next(); 291 | if (predicate.apply(element)) { 292 | return element; 293 | } 294 | } 295 | return endOfData(); 296 | } 297 | }; 298 | } 299 | 300 | /** 301 | * Returns all instances of class {@code type} in {@code unfiltered}. The 302 | * returned iterator has elements whose class is {@code type} or a subclass of 303 | * {@code type}. 304 | * 305 | * @param unfiltered an iterator containing objects of any type 306 | * @param type the type of elements desired 307 | * @return an unmodifiable iterator containing all elements of the original 308 | * iterator that were of the requested type 309 | */ 310 | @SuppressWarnings("unchecked") // can cast to because non-Ts are removed 311 | public static UnmodifiableIterator filter(Iterator unfiltered, Class type) { 312 | return (UnmodifiableIterator) filter(unfiltered, Predicates.instanceOf(type)); 313 | } 314 | 315 | /** 316 | * Returns {@code true} if one or more elements returned by {@code iterator} 317 | * satisfy the given predicate. 318 | */ 319 | public static boolean any(Iterator iterator, Predicate predicate) { 320 | return indexOf(iterator, predicate) != -1; 321 | } 322 | 323 | /** 324 | * Returns {@code true} if every element returned by {@code iterator} 325 | * satisfies the given predicate. If {@code iterator} is empty, {@code true} 326 | * is returned. 327 | */ 328 | public static boolean all(Iterator iterator, Predicate predicate) { 329 | Preconditions.checkNotNull(predicate); 330 | while (iterator.hasNext()) { 331 | T element = iterator.next(); 332 | if (!predicate.apply(element)) { 333 | return false; 334 | } 335 | } 336 | return true; 337 | } 338 | 339 | /** 340 | * Returns the first element in {@code iterator} that satisfies the given 341 | * predicate; use this method only when such an element is known to exist. If 342 | * no such element is found, the iterator will be left exhausted: its {@code 343 | * hasNext()} method will return {@code false}. If it is possible that 344 | * no element will match, use {@link #tryFind} or {@link 345 | * #find(Iterator, Predicate, Object)} instead. 346 | * 347 | * @throws NoSuchElementException if no element in {@code iterator} matches 348 | * the given predicate 349 | */ 350 | public static T find(Iterator iterator, Predicate predicate) { 351 | return filter(iterator, predicate).next(); 352 | } 353 | 354 | /** 355 | * Returns the first element in {@code iterator} that satisfies the given 356 | * predicate. If no such element is found, {@code defaultValue} will be 357 | * returned from this method and the iterator will be left exhausted: its 358 | * {@code hasNext()} method will return {@code false}. Note that this can 359 | * usually be handled more naturally using {@code 360 | * tryFind(iterator, predicate).or(defaultValue)}. 361 | * 362 | * @since 7.0 363 | */ 364 | @Nullable 365 | public static T find(Iterator iterator, Predicate predicate, 366 | @Nullable T defaultValue) { 367 | return getNext(filter(iterator, predicate), defaultValue); 368 | } 369 | 370 | /** 371 | * Returns an {@link Optional} containing the first element in {@code 372 | * iterator} that satisfies the given predicate, if such an element exists. If 373 | * no such element is found, an empty {@link Optional} will be returned from 374 | * this method and the iterator will be left exhausted: its {@code 375 | * hasNext()} method will return {@code false}. 376 | * 377 | *

Warning: avoid using a {@code predicate} that matches {@code 378 | * null}. If {@code null} is matched in {@code iterator}, a 379 | * NullPointerException will be thrown. 380 | * 381 | * @since 11.0 382 | */ 383 | public static Optional tryFind(Iterator iterator, Predicate predicate) { 384 | UnmodifiableIterator filteredIterator = filter(iterator, predicate); 385 | return filteredIterator.hasNext() 386 | ? Optional.of(filteredIterator.next()) 387 | : Optional.absent(); 388 | } 389 | 390 | /** 391 | * Returns the index in {@code iterator} of the first element that satisfies 392 | * the provided {@code predicate}, or {@code -1} if the Iterator has no such 393 | * elements. 394 | * 395 | *

More formally, returns the lowest index {@code i} such that 396 | * {@code predicate.apply(Iterators.get(iterator, i))} returns {@code true}, 397 | * or {@code -1} if there is no such index. 398 | * 399 | *

If -1 is returned, the iterator will be left exhausted: its 400 | * {@code hasNext()} method will return {@code false}. Otherwise, 401 | * the iterator will be set to the element which satisfies the 402 | * {@code predicate}. 403 | * 404 | * @since 2.0 405 | */ 406 | public static int indexOf(Iterator iterator, Predicate predicate) { 407 | Preconditions.checkNotNull(predicate, "predicate"); 408 | for (int i = 0; iterator.hasNext(); i++) { 409 | T current = iterator.next(); 410 | if (predicate.apply(current)) { 411 | return i; 412 | } 413 | } 414 | return -1; 415 | } 416 | 417 | /** 418 | * Advances {@code iterator} {@code position + 1} times, returning the 419 | * element at the {@code position}th position. 420 | * 421 | * @param position position of the element to return 422 | * @return the element at the specified position in {@code iterator} 423 | * @throws IndexOutOfBoundsException if {@code position} is negative or 424 | * greater than or equal to the number of elements remaining in 425 | * {@code iterator} 426 | */ 427 | public static T get(Iterator iterator, int position) { 428 | CollectPreconditions.checkIndexNonnegative(position); 429 | int skipped = advance(iterator, position); 430 | if (!iterator.hasNext()) { 431 | throw new IndexOutOfBoundsException("position (" + position 432 | + ") must be less than the number of elements that remained (" 433 | + skipped + ")"); 434 | } 435 | return iterator.next(); 436 | } 437 | 438 | /** 439 | * Advances {@code iterator} {@code position + 1} times, returning the 440 | * element at the {@code position}th position or {@code defaultValue} 441 | * otherwise. 442 | * 443 | * @param position position of the element to return 444 | * @param defaultValue the default value to return if the iterator is empty 445 | * or if {@code position} is greater than the number of elements 446 | * remaining in {@code iterator} 447 | * @return the element at the specified position in {@code iterator} or 448 | * {@code defaultValue} if {@code iterator} produces fewer than 449 | * {@code position + 1} elements. 450 | * @throws IndexOutOfBoundsException if {@code position} is negative 451 | * @since 4.0 452 | */ 453 | @Nullable 454 | public static T get(Iterator iterator, int position, @Nullable T defaultValue) { 455 | CollectPreconditions.checkIndexNonnegative(position); 456 | advance(iterator, position); 457 | return getNext(iterator, defaultValue); 458 | } 459 | 460 | /** 461 | * Returns the next element in {@code iterator} or {@code defaultValue} if 462 | * the iterator is empty. The {@link Iterables} analog to this method is 463 | * {@link Iterables#getFirst}. 464 | * 465 | * @param defaultValue the default value to return if the iterator is empty 466 | * @return the next element of {@code iterator} or the default value 467 | * @since 7.0 468 | */ 469 | @Nullable 470 | public static T getNext(Iterator iterator, @Nullable T defaultValue) { 471 | return iterator.hasNext() ? iterator.next() : defaultValue; 472 | } 473 | 474 | /** 475 | * Advances {@code iterator} to the end, returning the last element. 476 | * 477 | * @return the last element of {@code iterator} 478 | * @throws NoSuchElementException if the iterator is empty 479 | */ 480 | public static T getLast(Iterator iterator) { 481 | while (true) { 482 | T current = iterator.next(); 483 | if (!iterator.hasNext()) { 484 | return current; 485 | } 486 | } 487 | } 488 | 489 | /** 490 | * Advances {@code iterator} to the end, returning the last element or 491 | * {@code defaultValue} if the iterator is empty. 492 | * 493 | * @param defaultValue the default value to return if the iterator is empty 494 | * @return the last element of {@code iterator} 495 | * @since 3.0 496 | */ 497 | @Nullable 498 | public static T getLast(Iterator iterator, @Nullable T defaultValue) { 499 | return iterator.hasNext() ? getLast(iterator) : defaultValue; 500 | } 501 | 502 | /** 503 | * Calls {@code next()} on {@code iterator}, either {@code numberToAdvance} times 504 | * or until {@code hasNext()} returns {@code false}, whichever comes first. 505 | * 506 | * @return the number of elements the iterator was advanced 507 | * @since 13.0 (since 3.0 as {@code Iterators.skip}) 508 | */ 509 | public static int advance(Iterator iterator, int numberToAdvance) { 510 | Preconditions.checkNotNull(iterator); 511 | Preconditions.checkArgument(numberToAdvance >= 0, "numberToAdvance must be nonnegative"); 512 | 513 | int i; 514 | for (i = 0; i < numberToAdvance && iterator.hasNext(); i++) { 515 | iterator.next(); 516 | } 517 | return i; 518 | } 519 | 520 | // Methods only in Iterators, not in Iterables 521 | 522 | /** 523 | * Clears the iterator using its remove method. 524 | */ 525 | static void clear(Iterator iterator) { 526 | Preconditions.checkNotNull(iterator); 527 | while (iterator.hasNext()) { 528 | iterator.next(); 529 | iterator.remove(); 530 | } 531 | } 532 | } 533 | -------------------------------------------------------------------------------- /src/main/java/com/fernandocejas/arrow/collections/Iterables.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2007 The Guava Authors 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 | package com.fernandocejas.arrow.collections; 17 | 18 | import com.fernandocejas.arrow.checks.Preconditions; 19 | import com.fernandocejas.arrow.functions.Predicate; 20 | import com.fernandocejas.arrow.optional.Optional; 21 | import java.util.Collection; 22 | import java.util.Iterator; 23 | import java.util.List; 24 | import java.util.NoSuchElementException; 25 | import java.util.RandomAccess; 26 | import org.jetbrains.annotations.Nullable; 27 | 28 | import static com.fernandocejas.arrow.checks.Preconditions.checkNotNull; 29 | import static com.fernandocejas.arrow.collections.CollectPreconditions.checkIndexNonnegative; 30 | 31 | /** 32 | * This class contains static utility methods that operate on or return objects 33 | * of type {@code Iterable}. Except as noted, each method has a corresponding 34 | * {@link Iterator}-based method in the {@link Iterators} class. 35 | * 36 | *

Performance notes: Unless otherwise noted, all of the iterables 37 | * produced in this class are lazy, which means that their iterators 38 | * only advance the backing iteration when absolutely necessary. 39 | * 40 | *

See the Guava User Guide article on 42 | * {@code Iterables}. 43 | * 44 | * @author Kevin Bourrillion 45 | * @author Jared Levy 46 | * @since 2.0 (imported from Google Collections Library) 47 | */ 48 | public final class Iterables { 49 | /** 50 | * Returns the number of elements in {@code iterable}. 51 | */ 52 | public static int size(Iterable iterable) { 53 | return iterable instanceof Collection 54 | ? ((Collection) iterable).size() 55 | : Iterators.size(iterable.iterator()); 56 | } 57 | 58 | /** 59 | * Returns {@code true} if {@code iterable} contains any object for which {@code equals(element)} 60 | * is true. 61 | */ 62 | public static boolean contains(Iterable iterable, @Nullable Object element) { 63 | if (iterable instanceof Collection) { 64 | Collection collection = (Collection) iterable; 65 | return MoreCollections.safeContains(collection, element); 66 | } 67 | return Iterators.contains(iterable.iterator(), element); 68 | } 69 | 70 | /** 71 | * Divides an iterable into unmodifiable sublists of the given size (the final 72 | * iterable may be smaller). For example, partitioning an iterable containing 73 | * {@code [a, b, c, d, e]} with a partition size of 3 yields {@code 74 | * [[a, b, c], [d, e]]} -- an outer iterable containing two inner lists of 75 | * three and two elements, all in the original order. 76 | * 77 | *

Iterators returned by the returned iterable do not support the {@link 78 | * Iterator#remove()} method. The returned lists implement {@link 79 | * RandomAccess}, whether or not the input list does. 80 | * 81 | *

Note: if {@code iterable} is a {@link List}, use {@link 82 | * Lists#partition(List, int)} instead. 83 | * 84 | * @param iterable the iterable to return a partitioned view of 85 | * @param size the desired size of each partition (the last may be smaller) 86 | * @return an iterable of unmodifiable lists containing the elements of {@code 87 | * iterable} divided into partitions 88 | * @throws IllegalArgumentException if {@code size} is nonpositive 89 | */ 90 | public static Iterable> partition( 91 | final Iterable iterable, final int size) { 92 | checkNotNull(iterable); 93 | Preconditions.checkArgument(size > 0); 94 | return new Iterable>() { 95 | @Override 96 | public Iterator> iterator() { 97 | return Iterators.partition(iterable.iterator(), size); 98 | } 99 | }; 100 | } 101 | 102 | /** 103 | * Divides an iterable into unmodifiable sublists of the given size, padding 104 | * the final iterable with null values if necessary. For example, partitioning 105 | * an iterable containing {@code [a, b, c, d, e]} with a partition size of 3 106 | * yields {@code [[a, b, c], [d, e, null]]} -- an outer iterable containing 107 | * two inner lists of three elements each, all in the original order. 108 | * 109 | *

Iterators returned by the returned iterable do not support the {@link 110 | * Iterator#remove()} method. 111 | * 112 | * @param iterable the iterable to return a partitioned view of 113 | * @param size the desired size of each partition 114 | * @return an iterable of unmodifiable lists containing the elements of {@code 115 | * iterable} divided into partitions (the final iterable may have 116 | * trailing null elements) 117 | * @throws IllegalArgumentException if {@code size} is nonpositive 118 | */ 119 | public static Iterable> paddedPartition( 120 | final Iterable iterable, final int size) { 121 | checkNotNull(iterable); 122 | Preconditions.checkArgument(size > 0); 123 | return new Iterable>() { 124 | @Override 125 | public Iterator> iterator() { 126 | return Iterators.paddedPartition(iterable.iterator(), size); 127 | } 128 | }; 129 | } 130 | 131 | /** 132 | * Returns the elements of {@code unfiltered} that satisfy a predicate. The 133 | * resulting iterable's iterator does not support {@code remove()}. 134 | */ 135 | public static Iterable filter( 136 | final Iterable unfiltered, final Predicate predicate) { 137 | checkNotNull(unfiltered); 138 | checkNotNull(predicate); 139 | return new Iterable() { 140 | @Override 141 | public Iterator iterator() { 142 | return Iterators.filter(unfiltered.iterator(), predicate); 143 | } 144 | }; 145 | } 146 | 147 | /** 148 | * Returns all instances of class {@code type} in {@code unfiltered}. The 149 | * returned iterable has elements whose class is {@code type} or a subclass of 150 | * {@code type}. The returned iterable's iterator does not support 151 | * {@code remove()}. 152 | * 153 | * @param unfiltered an iterable containing objects of any type 154 | * @param type the type of elements desired 155 | * @return an unmodifiable iterable containing all elements of the original 156 | * iterable that were of the requested type 157 | */ 158 | public static Iterable filter( 159 | final Iterable unfiltered, final Class type) { 160 | checkNotNull(unfiltered); 161 | checkNotNull(type); 162 | return new Iterable() { 163 | @Override 164 | public Iterator iterator() { 165 | return Iterators.filter(unfiltered.iterator(), type); 166 | } 167 | }; 168 | } 169 | 170 | /** 171 | * Removes, from an iterable, every element that belongs to the provided 172 | * collection. 173 | * 174 | *

This method calls {@link Collection#removeAll} if {@code iterable} is a 175 | * collection, and {@link Iterators#removeAll} otherwise. 176 | * 177 | * @param removeFrom the iterable to (potentially) remove elements from 178 | * @param elementsToRemove the elements to remove 179 | * @return {@code true} if any element was removed from {@code iterable} 180 | */ 181 | public static boolean removeAll( 182 | Iterable removeFrom, Collection elementsToRemove) { 183 | return removeFrom instanceof Collection 184 | ? ((Collection) removeFrom).removeAll(checkNotNull(elementsToRemove)) 185 | : Iterators.removeAll(removeFrom.iterator(), elementsToRemove); 186 | } 187 | 188 | /** 189 | * Removes, from an iterable, every element that does not belong to the 190 | * provided collection. 191 | * 192 | *

This method calls {@link Collection#retainAll} if {@code iterable} is a 193 | * collection, and {@link Iterators#retainAll} otherwise. 194 | * 195 | * @param removeFrom the iterable to (potentially) remove elements from 196 | * @param elementsToRetain the elements to retain 197 | * @return {@code true} if any element was removed from {@code iterable} 198 | */ 199 | public static boolean retainAll( 200 | Iterable removeFrom, Collection elementsToRetain) { 201 | return removeFrom instanceof Collection 202 | ? ((Collection) removeFrom).retainAll(checkNotNull(elementsToRetain)) 203 | : Iterators.retainAll(removeFrom.iterator(), elementsToRetain); 204 | } 205 | 206 | /** 207 | * Removes, from an iterable, every element that satisfies the provided 208 | * predicate. 209 | * 210 | * @param removeFrom the iterable to (potentially) remove elements from 211 | * @param predicate a predicate that determines whether an element should 212 | * be removed 213 | * @return {@code true} if any elements were removed from the iterable 214 | * @throws UnsupportedOperationException if the iterable does not support 215 | * {@code remove()}. 216 | * @since 2.0 217 | */ 218 | public static boolean removeIf( 219 | Iterable removeFrom, Predicate predicate) { 220 | if (removeFrom instanceof RandomAccess && removeFrom instanceof List) { 221 | return removeIfFromRandomAccessList( 222 | (List) removeFrom, checkNotNull(predicate)); 223 | } 224 | return Iterators.removeIf(removeFrom.iterator(), predicate); 225 | } 226 | 227 | private static boolean removeIfFromRandomAccessList( 228 | List list, Predicate predicate) { 229 | // Note: Not all random access lists support set() so we need to deal with 230 | // those that don't and attempt the slower remove() based solution. 231 | int from = 0; 232 | int to = 0; 233 | 234 | for (; from < list.size(); from++) { 235 | T element = list.get(from); 236 | if (!predicate.apply(element)) { 237 | if (from > to) { 238 | try { 239 | list.set(to, element); 240 | } catch (UnsupportedOperationException e) { 241 | slowRemoveIfForRemainingElements(list, predicate, to, from); 242 | return true; 243 | } 244 | } 245 | to++; 246 | } 247 | } 248 | 249 | // Clear the tail of any remaining items 250 | list.subList(to, list.size()).clear(); 251 | return from != to; 252 | } 253 | 254 | private static void slowRemoveIfForRemainingElements(List list, 255 | Predicate predicate, int to, int from) { 256 | // Here we know that: 257 | // * (to < from) and that both are valid indices. 258 | // * Everything with (index < to) should be kept. 259 | // * Everything with (to <= index < from) should be removed. 260 | // * The element with (index == from) should be kept. 261 | // * Everything with (index > from) has not been checked yet. 262 | 263 | // Check from the end of the list backwards (minimize expected cost of 264 | // moving elements when remove() is called). Stop before 'from' because 265 | // we already know that should be kept. 266 | for (int n = list.size() - 1; n > from; n--) { 267 | if (predicate.apply(list.get(n))) { 268 | list.remove(n); 269 | } 270 | } 271 | // And now remove everything in the range [to, from) (going backwards). 272 | for (int n = from - 1; n >= to; n--) { 273 | list.remove(n); 274 | } 275 | } 276 | 277 | /** 278 | * Removes and returns the first matching element, or returns {@code null} if there is none. 279 | */ 280 | @Nullable 281 | static T removeFirstMatching(Iterable removeFrom, Predicate predicate) { 282 | checkNotNull(predicate); 283 | Iterator iterator = removeFrom.iterator(); 284 | while (iterator.hasNext()) { 285 | T next = iterator.next(); 286 | if (predicate.apply(next)) { 287 | iterator.remove(); 288 | return next; 289 | } 290 | } 291 | return null; 292 | } 293 | 294 | /** 295 | * Determines whether two iterables contain equal elements in the same order. 296 | * More specifically, this method returns {@code true} if {@code iterable1} 297 | * and {@code iterable2} contain the same number of elements and every element 298 | * of {@code iterable1} is equal to the corresponding element of 299 | * {@code iterable2}. 300 | */ 301 | public static boolean elementsEqual( 302 | Iterable iterable1, Iterable iterable2) { 303 | if (iterable1 instanceof Collection && iterable2 instanceof Collection) { 304 | Collection collection1 = (Collection) iterable1; 305 | Collection collection2 = (Collection) iterable2; 306 | if (collection1.size() != collection2.size()) { 307 | return false; 308 | } 309 | } 310 | return Iterators.elementsEqual(iterable1.iterator(), iterable2.iterator()); 311 | } 312 | 313 | /** 314 | * Returns a string representation of {@code iterable}, with the format {@code 315 | * [e1, e2, ..., en]} (that is, identical to {@link java.util.Arrays 316 | * Arrays}{@code .toString(Iterables.toArray(iterable))}). Note that for 317 | * most implementations of {@link Collection}, {@code 318 | * collection.toString()} also gives the same result, but that behavior is not 319 | * generally guaranteed. 320 | */ 321 | public static String toString(Iterable iterable) { 322 | return Iterators.toString(iterable.iterator()); 323 | } 324 | 325 | /** 326 | * Returns the single element contained in {@code iterable}. 327 | * 328 | * @throws NoSuchElementException if the iterable is empty 329 | * @throws IllegalArgumentException if the iterable contains multiple 330 | * elements 331 | */ 332 | public static T getOnlyElement(Iterable iterable) { 333 | return Iterators.getOnlyElement(iterable.iterator()); 334 | } 335 | 336 | /** 337 | * Returns the single element contained in {@code iterable}, or {@code 338 | * defaultValue} if the iterable is empty. 339 | * 340 | * @throws IllegalArgumentException if the iterator contains multiple 341 | * elements 342 | */ 343 | @Nullable 344 | public static T getOnlyElement( 345 | Iterable iterable, @Nullable T defaultValue) { 346 | return Iterators.getOnlyElement(iterable.iterator(), defaultValue); 347 | } 348 | 349 | /** 350 | * Converts an iterable into a collection. If the iterable is already a 351 | * collection, it is returned. Otherwise, an {@link java.util.ArrayList} is 352 | * created with the contents of the iterable in the same iteration order. 353 | */ 354 | private static Collection toCollection(Iterable iterable) { 355 | return iterable instanceof Collection 356 | ? (Collection) iterable 357 | : Lists.newArrayList(iterable.iterator()); 358 | } 359 | 360 | /** 361 | * Adds all elements in {@code iterable} to {@code collection}. 362 | * 363 | * @return {@code true} if {@code collection} was modified as a result of this 364 | * operation. 365 | */ 366 | public static boolean addAll( 367 | Collection addTo, Iterable elementsToAdd) { 368 | if (elementsToAdd instanceof Collection) { 369 | Collection c = MoreCollections.cast(elementsToAdd); 370 | return addTo.addAll(c); 371 | } 372 | return Iterators.addAll(addTo, checkNotNull(elementsToAdd).iterator()); 373 | } 374 | 375 | /** 376 | * Returns {@code true} if any element in {@code iterable} satisfies the predicate. 377 | */ 378 | public static boolean any( 379 | Iterable iterable, Predicate predicate) { 380 | return Iterators.any(iterable.iterator(), predicate); 381 | } 382 | 383 | /** 384 | * Returns {@code true} if every element in {@code iterable} satisfies the 385 | * predicate. If {@code iterable} is empty, {@code true} is returned. 386 | */ 387 | public static boolean all( 388 | Iterable iterable, Predicate predicate) { 389 | return Iterators.all(iterable.iterator(), predicate); 390 | } 391 | 392 | /** 393 | * Returns the first element in {@code iterable} that satisfies the given 394 | * predicate; use this method only when such an element is known to exist. If 395 | * it is possible that no element will match, use {@link #tryFind} or 396 | * {@link #find(Iterable, Predicate, Object)} instead. 397 | * 398 | * @throws NoSuchElementException if no element in {@code iterable} matches 399 | * the given predicate 400 | */ 401 | public static T find(Iterable iterable, 402 | Predicate predicate) { 403 | return Iterators.find(iterable.iterator(), predicate); 404 | } 405 | 406 | /** 407 | * Returns the first element in {@code iterable} that satisfies the given 408 | * predicate, or {@code defaultValue} if none found. Note that this can 409 | * usually be handled more naturally using {@code 410 | * tryFind(iterable, predicate).or(defaultValue)}. 411 | * 412 | * @since 7.0 413 | */ 414 | @Nullable 415 | public static T find(Iterable iterable, 416 | Predicate predicate, @Nullable T defaultValue) { 417 | return Iterators.find(iterable.iterator(), predicate, defaultValue); 418 | } 419 | 420 | /** 421 | * Returns an {@link Optional} containing the first element in {@code 422 | * iterable} that satisfies the given predicate, if such an element exists. 423 | * 424 | *

Warning: avoid using a {@code predicate} that matches {@code 425 | * null}. If {@code null} is matched in {@code iterable}, a 426 | * NullPointerException will be thrown. 427 | * 428 | * @since 11.0 429 | */ 430 | public static Optional tryFind(Iterable iterable, 431 | Predicate predicate) { 432 | return Iterators.tryFind(iterable.iterator(), predicate); 433 | } 434 | 435 | /** 436 | * Returns the index in {@code iterable} of the first element that satisfies 437 | * the provided {@code predicate}, or {@code -1} if the Iterable has no such 438 | * elements. 439 | * 440 | *

More formally, returns the lowest index {@code i} such that 441 | * {@code predicate.apply(Iterables.get(iterable, i))} returns {@code true}, 442 | * or {@code -1} if there is no such index. 443 | * 444 | * @since 2.0 445 | */ 446 | public static int indexOf( 447 | Iterable iterable, Predicate predicate) { 448 | return Iterators.indexOf(iterable.iterator(), predicate); 449 | } 450 | 451 | /** 452 | * Returns the element at the specified position in an iterable. 453 | * 454 | * @param position position of the element to return 455 | * @return the element at the specified position in {@code iterable} 456 | * @throws IndexOutOfBoundsException if {@code position} is negative or 457 | * greater than or equal to the size of {@code iterable} 458 | */ 459 | public static T get(Iterable iterable, int position) { 460 | checkNotNull(iterable); 461 | return iterable instanceof List 462 | ? ((List) iterable).get(position) 463 | : Iterators.get(iterable.iterator(), position); 464 | } 465 | 466 | /** 467 | * Returns the element at the specified position in an iterable or a default 468 | * value otherwise. 469 | * 470 | * @param position position of the element to return 471 | * @param defaultValue the default value to return if {@code position} is 472 | * greater than or equal to the size of the iterable 473 | * @return the element at the specified position in {@code iterable} or 474 | * {@code defaultValue} if {@code iterable} contains fewer than 475 | * {@code position + 1} elements. 476 | * @throws IndexOutOfBoundsException if {@code position} is negative 477 | * @since 4.0 478 | */ 479 | @Nullable 480 | public static T get(Iterable iterable, int position, @Nullable T defaultValue) { 481 | checkNotNull(iterable); 482 | checkIndexNonnegative(position); 483 | if (iterable instanceof List) { 484 | List list = Lists.cast(iterable); 485 | return position < list.size() ? list.get(position) : defaultValue; 486 | } else { 487 | Iterator iterator = iterable.iterator(); 488 | Iterators.advance(iterator, position); 489 | return Iterators.getNext(iterator, defaultValue); 490 | } 491 | } 492 | 493 | /** 494 | * Returns the first element in {@code iterable} or {@code defaultValue} if 495 | * the iterable is empty. The {@link Iterators} analog to this method is 496 | * {@link Iterators#getNext}. 497 | * 498 | *

If no default value is desired (and the caller instead wants a 499 | * {@link NoSuchElementException} to be thrown), it is recommended that 500 | * {@code iterable.iterator().next()} is used instead. 501 | * 502 | * @param defaultValue the default value to return if the iterable is empty 503 | * @return the first element of {@code iterable} or the default value 504 | * @since 7.0 505 | */ 506 | @Nullable 507 | public static T getFirst(Iterable iterable, @Nullable T defaultValue) { 508 | return Iterators.getNext(iterable.iterator(), defaultValue); 509 | } 510 | 511 | /** 512 | * Returns the last element of {@code iterable}. 513 | * 514 | * @return the last element of {@code iterable} 515 | * @throws NoSuchElementException if the iterable is empty 516 | */ 517 | public static T getLast(Iterable iterable) { 518 | // TODO(kevinb): Support a concurrently modified collection? 519 | if (iterable instanceof List) { 520 | List list = (List) iterable; 521 | if (list.isEmpty()) { 522 | throw new NoSuchElementException(); 523 | } 524 | return getLastInNonemptyList(list); 525 | } 526 | 527 | return Iterators.getLast(iterable.iterator()); 528 | } 529 | 530 | /** 531 | * Returns the last element of {@code iterable} or {@code defaultValue} if 532 | * the iterable is empty. 533 | * 534 | * @param defaultValue the value to return if {@code iterable} is empty 535 | * @return the last element of {@code iterable} or the default value 536 | * @since 3.0 537 | */ 538 | @Nullable 539 | public static T getLast(Iterable iterable, @Nullable T defaultValue) { 540 | if (iterable instanceof Collection) { 541 | Collection c = MoreCollections.cast(iterable); 542 | if (c.isEmpty()) { 543 | return defaultValue; 544 | } else if (iterable instanceof List) { 545 | return getLastInNonemptyList(Lists.cast(iterable)); 546 | } 547 | } 548 | 549 | return Iterators.getLast(iterable.iterator(), defaultValue); 550 | } 551 | 552 | private static T getLastInNonemptyList(List list) { 553 | return list.get(list.size() - 1); 554 | } 555 | 556 | // Methods only in Iterables, not in Iterators 557 | 558 | /** 559 | * Determines if the given iterable contains no elements. 560 | * 561 | *

There is no precise {@link Iterator} equivalent to this method, since 562 | * one can only ask an iterator whether it has any elements remaining 563 | * (which one does using {@link Iterator#hasNext}). 564 | * 565 | * @return {@code true} if the iterable contains no elements 566 | */ 567 | public static boolean isEmpty(Iterable iterable) { 568 | if (iterable instanceof Collection) { 569 | return ((Collection) iterable).isEmpty(); 570 | } 571 | return !iterable.iterator().hasNext(); 572 | } 573 | 574 | private Iterables() { 575 | // no instances 576 | } 577 | } 578 | 579 | --------------------------------------------------------------------------------