001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.io.function;
019
020import java.io.IOException;
021import java.io.UncheckedIOException;
022import java.util.Objects;
023import java.util.function.Consumer;
024import java.util.function.Function;
025import java.util.function.Supplier;
026
027/**
028 * Like {@link Function} but throws {@link IOException}.
029 *
030 * @param <T> the type of the input to the operations.
031 * @param <R> the return type of the operations.
032 * @since 2.7
033 */
034@FunctionalInterface
035public interface IOFunction<T, R> {
036
037    /**
038     * Returns a {@link IOFunction} that always returns its input argument.
039     *
040     * @param <T> the type of the input and output objects to the function
041     * @return a function that always returns its input argument
042     */
043    @SuppressWarnings("unchecked")
044    static <T> IOFunction<T, T> identity() {
045        return Constants.IO_FUNCTION_ID;
046    }
047
048    /**
049     * Returns a composed {@link IOFunction} that first applies this function to its input, and then applies the
050     * {@code after} consumer to the result. If evaluation of either function throws an exception, it is relayed to the
051     * caller of the composed function.
052     *
053     * @param after the consumer to apply after this function is applied
054     * @return a composed function that first applies this function and then applies the {@code after} consumer
055     * @throws NullPointerException if after is null
056     * @see #compose(IOFunction)
057     */
058    default IOConsumer<T> andThen(final Consumer<? super R> after) {
059        Objects.requireNonNull(after, "after");
060        return (final T t) -> after.accept(apply(t));
061    }
062
063    /**
064     * Returns a composed {@link IOFunction} that first applies this function to its input, and then applies the
065     * {@code after} function to the result. If evaluation of either function throws an exception, it is relayed to the
066     * caller of the composed function.
067     *
068     * @param <V> the type of output of the {@code after} function, and of the composed function
069     * @param after the function to apply after this function is applied
070     * @return a composed function that first applies this function and then applies the {@code after} function
071     * @throws NullPointerException if after is null
072     * @see #compose(IOFunction)
073     */
074    default <V> IOFunction<T, V> andThen(final Function<? super R, ? extends V> after) {
075        Objects.requireNonNull(after, "after");
076        return (final T t) -> after.apply(apply(t));
077    }
078
079    /**
080     * Returns a composed {@link IOFunction} that first applies this function to its input, and then applies the
081     * {@code after} consumer to the result. If evaluation of either function throws an exception, it is relayed to the
082     * caller of the composed function.
083     *
084     * @param after the consumer to apply after this function is applied
085     * @return a composed function that first applies this function and then applies the {@code after} consumer
086     * @throws NullPointerException if after is null
087     * @see #compose(IOFunction)
088     */
089    default IOConsumer<T> andThen(final IOConsumer<? super R> after) {
090        Objects.requireNonNull(after, "after");
091        return (final T t) -> after.accept(apply(t));
092    }
093
094    /**
095     * Returns a composed {@link IOFunction} that first applies this function to its input, and then applies the
096     * {@code after} function to the result. If evaluation of either function throws an exception, it is relayed to the
097     * caller of the composed function.
098     *
099     * @param <V> the type of output of the {@code after} function, and of the composed function
100     * @param after the function to apply after this function is applied
101     * @return a composed function that first applies this function and then applies the {@code after} function
102     * @throws NullPointerException if after is null
103     * @see #compose(IOFunction)
104     */
105    default <V> IOFunction<T, V> andThen(final IOFunction<? super R, ? extends V> after) {
106        Objects.requireNonNull(after, "after");
107        return (final T t) -> after.apply(apply(t));
108    }
109
110    /**
111     * Applies this function to the given argument.
112     *
113     * @param t the function argument
114     * @return the function result
115     * @throws IOException if an I/O error occurs.
116     */
117    R apply(T t) throws IOException;
118
119    /**
120     * Creates a {@link Function} for this instance that throws {@link UncheckedIOException} instead of {@link IOException}.
121     *
122     * @return an UncheckedIOException Function.
123     * @since 2.12.0
124     */
125    default Function<T, R> asFunction() {
126        return t -> Uncheck.apply(this, t);
127    }
128
129    /**
130     * Returns a composed {@link IOFunction} that first applies the {@code before} function to its input, and then applies
131     * this function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
132     * composed function.
133     *
134     * @param <V> the type of input to the {@code before} function, and to the composed function
135     * @param before the function to apply before this function is applied
136     * @return a composed function that first applies the {@code before} function and then applies this function
137     * @throws NullPointerException if before is null
138     * @see #andThen(IOFunction)
139     */
140    default <V> IOFunction<V, R> compose(final Function<? super V, ? extends T> before) {
141        Objects.requireNonNull(before, "before");
142        return (final V v) -> apply(before.apply(v));
143    }
144
145    /**
146     * Returns a composed {@link IOFunction} that first applies the {@code before} function to its input, and then applies
147     * this function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
148     * composed function.
149     *
150     * @param <V> the type of input to the {@code before} function, and to the composed function
151     * @param before the function to apply before this function is applied
152     * @return a composed function that first applies the {@code before} function and then applies this function
153     * @throws NullPointerException if before is null
154     * @see #andThen(IOFunction)
155     */
156    default <V> IOFunction<V, R> compose(final IOFunction<? super V, ? extends T> before) {
157        Objects.requireNonNull(before, "before");
158        return (final V v) -> apply(before.apply(v));
159    }
160
161    /**
162     * Returns a composed {@link IOFunction} that first applies the {@code before} function to its input, and then applies
163     * this function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
164     * composed function.
165     *
166     * @param before the supplier which feeds the application of this function
167     * @return a composed function that first applies the {@code before} function and then applies this function
168     * @throws NullPointerException if before is null
169     * @see #andThen(IOFunction)
170     */
171    default IOSupplier<R> compose(final IOSupplier<? extends T> before) {
172        Objects.requireNonNull(before, "before");
173        return () -> apply(before.get());
174    }
175
176    /**
177     * Returns a composed {@link IOFunction} that first applies the {@code before} function to its input, and then applies
178     * this function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
179     * composed function.
180     *
181     * @param before the supplier which feeds the application of this function
182     * @return a composed function that first applies the {@code before} function and then applies this function
183     * @throws NullPointerException if before is null
184     * @see #andThen(IOFunction)
185     */
186    default IOSupplier<R> compose(final Supplier<? extends T> before) {
187        Objects.requireNonNull(before, "before");
188        return () -> apply(before.get());
189    }
190}