diff --git a/src/main/java/org/cactoos/scalar/FirstOf.java b/src/main/java/org/cactoos/scalar/FirstOf.java new file mode 100644 index 0000000000..6058d3c07c --- /dev/null +++ b/src/main/java/org/cactoos/scalar/FirstOf.java @@ -0,0 +1,91 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.scalar; + +import java.util.NoSuchElementException; +import org.cactoos.Func; +import org.cactoos.Scalar; +import org.cactoos.iterable.Filtered; +import org.cactoos.iterable.HeadOf; +import org.cactoos.iterable.IterableOf; + +/** + * Find first element in a list that satisfies specified condition. + * + *

This class is thread-safe. + * + * @author Krzysztof Krason (Krzysztof.Krason@gmail.com) + * @version $Id$ + * @param Type of result + * @since 0.31 + */ +public final class FirstOf implements Scalar { + + /** + * Condition for getting the element. + */ + private final Func condition; + + /** + * Source iterable. + */ + private final Iterable source; + + /** + * Fallback used if no value matches. + */ + private final Scalar fallback; + + /** + * Constructor. + * @param cond Condition for getting the element + * @param src Source iterable + * @param fbck Fallback used if no value matches + */ + public FirstOf(final Func cond, final Iterable src, + final Scalar fbck) { + this.condition = cond; + this.source = src; + this.fallback = fbck; + } + + @Override + public T value() throws Exception { + return new ScalarWithFallback<>( + () -> new HeadOf<>( + 1, + new Filtered<>(this.condition, this.source) + ).iterator().next(), + new IterableOf>( + new FallbackFrom( + new IterableOf>( + NoSuchElementException.class + ), + t1 -> this.fallback.value() + ) + ), + t -> t + ).value(); + } +} diff --git a/src/test/java/org/cactoos/scalar/FirstOfTest.java b/src/test/java/org/cactoos/scalar/FirstOfTest.java new file mode 100644 index 0000000000..b8670412d9 --- /dev/null +++ b/src/test/java/org/cactoos/scalar/FirstOfTest.java @@ -0,0 +1,86 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.scalar; + +import org.cactoos.iterable.IterableOf; +import org.cactoos.iterable.IterableOfInts; +import org.cactoos.matchers.ScalarHasValue; +import org.hamcrest.MatcherAssert; +import org.junit.Test; + +/** + * Tests for {@link FirstOf}. + * + *

This class is thread-safe. + * + * @author Krzysztof Krason (Krzysztof.Krason@gmail.com) + * @version $Id$ + * @since 0.31 + * @checkstyle JavadocMethodCheck (500 lines) + */ +public final class FirstOfTest { + + @Test + public void returnsMatchingValue() { + final int value = 1; + MatcherAssert.assertThat( + "Didn't return the only matching element", + new FirstOf<>( + i -> i >= value, + new IterableOfInts(0, value), + () -> -1 + ), + new ScalarHasValue<>(value) + ); + } + + @Test + public void returnsFirstValueForMultipleMatchingOnes() { + final String value = "1"; + MatcherAssert.assertThat( + "Didn't return first matching element", + new FirstOf<>( + i -> !i.isEmpty(), + new IterableOf<>("1", "2"), + () -> "" + ), + new ScalarHasValue<>(value) + ); + } + + @Test + public void returnsFallbackIfNothingMatches() { + final String value = "abc"; + MatcherAssert.assertThat( + "Didn't return fallback", + new FirstOf<>( + i -> i.length() > 2, + new IterableOf<>("ab", "cd"), + () -> value + ), + new ScalarHasValue<>(value) + ); + } + +}