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     *
057     * @see #compose(IOFunction)
058     */
059    default IOConsumer<T> andThen(final Consumer<? super R> after) {
060        Objects.requireNonNull(after, "after");
061        return (final T t) -> after.accept(apply(t));
062    }
063
064    /**
065     * Returns a composed {@link IOFunction} that first applies this function to its input, and then applies the
066     * {@code after} function to the result. If evaluation of either function throws an exception, it is relayed to the
067     * caller of the composed function.
068     *
069     * @param <V> the type of output of the {@code after} function, and of the composed function
070     * @param after the function to apply after this function is applied
071     * @return a composed function that first applies this function and then applies the {@code after} function
072     * @throws NullPointerException if after is null
073     *
074     * @see #compose(IOFunction)
075     */
076    default <V> IOFunction<T, V> andThen(final Function<? super R, ? extends V> after) {
077        Objects.requireNonNull(after, "after");
078        return (final T t) -> after.apply(apply(t));
079    }
080
081    /**
082     * Returns a composed {@link IOFunction} that first applies this function to its input, and then applies the
083     * {@code after} consumer to the result. If evaluation of either function throws an exception, it is relayed to the
084     * caller of the composed function.
085     *
086     * @param after the consumer to apply after this function is applied
087     * @return a composed function that first applies this function and then applies the {@code after} consumer
088     * @throws NullPointerException if after is null
089     *
090     * @see #compose(IOFunction)
091     */
092    default IOConsumer<T> andThen(final IOConsumer<? super R> after) {
093        Objects.requireNonNull(after, "after");
094        return (final T t) -> after.accept(apply(t));
095    }
096
097    /**
098     * Returns a composed {@link IOFunction} that first applies this function to its input, and then applies the
099     * {@code after} function to the result. If evaluation of either function throws an exception, it is relayed to the
100     * caller of the composed function.
101     *
102     * @param <V> the type of output of the {@code after} function, and of the composed function
103     * @param after the function to apply after this function is applied
104     * @return a composed function that first applies this function and then applies the {@code after} function
105     * @throws NullPointerException if after is null
106     *
107     * @see #compose(IOFunction)
108     */
109    default <V> IOFunction<T, V> andThen(final IOFunction<? super R, ? extends V> after) {
110        Objects.requireNonNull(after, "after");
111        return (final T t) -> after.apply(apply(t));
112    }
113
114    /**
115     * Applies this function to the given argument.
116     *
117     * @param t the function argument
118     * @return the function result
119     * @throws IOException if an I/O error occurs.
120     */
121    R apply(final T t) throws IOException;
122
123    /**
124     * Creates a {@link Function} for this instance that throws {@link UncheckedIOException} instead of {@link IOException}.
125     *
126     * @return an UncheckedIOException Function.
127     * @since 2.12.0
128     */
129    default Function<T, R> asFunction() {
130        return t -> Uncheck.apply(this, t);
131    }
132
133    /**
134     * Returns a composed {@link IOFunction} that first applies the {@code before} function to its input, and then applies
135     * this function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
136     * composed function.
137     *
138     * @param <V> the type of input to the {@code before} function, and to the composed function
139     * @param before the function to apply before this function is applied
140     * @return a composed function that first applies the {@code before} function and then applies this function
141     * @throws NullPointerException if before is null
142     *
143     * @see #andThen(IOFunction)
144     */
145    default <V> IOFunction<V, R> compose(final Function<? super V, ? extends T> before) {
146        Objects.requireNonNull(before, "before");
147        return (final V v) -> apply(before.apply(v));
148    }
149
150    /**
151     * Returns a composed {@link IOFunction} that first applies the {@code before} function to its input, and then applies
152     * this function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
153     * composed function.
154     *
155     * @param <V> the type of input to the {@code before} function, and to the composed function
156     * @param before the function to apply before this function is applied
157     * @return a composed function that first applies the {@code before} function and then applies this function
158     * @throws NullPointerException if before is null
159     *
160     * @see #andThen(IOFunction)
161     */
162    default <V> IOFunction<V, R> compose(final IOFunction<? super V, ? extends T> before) {
163        Objects.requireNonNull(before, "before");
164        return (final V v) -> apply(before.apply(v));
165    }
166
167    /**
168     * Returns a composed {@link IOFunction} that first applies the {@code before} function to its input, and then applies
169     * this function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
170     * composed function.
171     *
172     * @param before the supplier which feeds the application of this function
173     * @return a composed function that first applies the {@code before} function and then applies this function
174     * @throws NullPointerException if before is null
175     *
176     * @see #andThen(IOFunction)
177     */
178    default IOSupplier<R> compose(final IOSupplier<? extends T> before) {
179        Objects.requireNonNull(before, "before");
180        return () -> apply(before.get());
181    }
182
183    /**
184     * Returns a composed {@link IOFunction} that first applies the {@code before} function to its input, and then applies
185     * this function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
186     * composed function.
187     *
188     * @param before the supplier which feeds the application of this function
189     * @return a composed function that first applies the {@code before} function and then applies this function
190     * @throws NullPointerException if before is null
191     *
192     * @see #andThen(IOFunction)
193     */
194    default IOSupplier<R> compose(final Supplier<? extends T> before) {
195        Objects.requireNonNull(before, "before");
196        return () -> apply(before.get());
197    }
198}