    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}