AutoCloseables.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.lang3;

import java.io.Closeable;
import java.util.function.Consumer;

import org.apache.commons.lang3.function.Consumers;
import org.apache.commons.lang3.function.FailableConsumer;

/**
 * Static operations on {@link AutoCloseable}.
 * <p>
 * For {@link Closeable}-specific methods, see Apache Commons IO's
 * <a href="https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/IOUtils.html">IOUtils</a>.
 * </p>
 *
 * @since 3.21.0
 */
public class AutoCloseables {

    /**
     * Closes the given {@link AutoCloseable} as a null-safe operation.
     *
     * @param closeable The resource to close, may be null.
     * @throws Exception if an error occurs.
     */
    public static void close(final AutoCloseable closeable) throws Exception {
        if (closeable != null) {
            closeable.close();
        }
    }

    /**
     * Closes the given {@link AutoCloseable} as a null-safe operation.
     *
     * @param closeable The resource to close, may be null.
     * @param consumer  Consume the Exception thrown by {@link AutoCloseable#close()}.
     * @throws Exception As thrown by the consumer.
     */
    public static void close(final AutoCloseable closeable, final FailableConsumer<Exception, Exception> consumer) throws Exception {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (final Exception e) {
                FailableConsumer.accept(consumer, e);
            }
        }
    }

    /**
     * Closes an {@link AutoCloseable}, never throwing an {@link Exception}.
     * <p>
     * Equivalent to {@link AutoCloseable#close()}, except any exceptions will be ignored.
     * </p>
     *
     * @param closeable the objects to close, may be null or already closed.
     * @see Throwable#addSuppressed(Throwable)
     */
    public static void closeQuietly(final AutoCloseable closeable) {
        closeQuietly(closeable, (Consumer<Exception>) null);
    }

    /**
     * Closes the given {@link AutoCloseable} as a null-safe operation while consuming Exception by the given {@code consumer}.
     *
     * @param closeable The resource to close, may be null.
     * @param consumer  Consumes the Exception thrown by {@link AutoCloseable#close()}.
     */
    public static void closeQuietly(final AutoCloseable closeable, final Consumer<Exception> consumer) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (final Exception e) {
                Consumers.accept(consumer, e);
            }
        }
    }

    /**
     * Closes an iterable of {@link AutoCloseable}, never throwing an {@link Exception}.
     * <p>
     * Equivalent calling {@link AutoCloseable#close()} on each element, except any exceptions will be ignored.
     * </p>
     *
     * @param closeables the objects to close, may be null or already closed.
     * @see #closeQuietly(AutoCloseable)
     */
    public static void closeQuietly(final Iterable<AutoCloseable> closeables) {
        if (closeables != null) {
            closeables.forEach(AutoCloseables::closeQuietly);
        }
    }

    /**
     * Closes a {@link Closeable} unconditionally and adds any exception thrown by the {@code close()} to the given Throwable.
     * <p>
     * For example:
     * </p>
     *
     * <pre>
     * AutoCloseable autoCloseable = ...;
     * try {
     *     // process autoCloseable.
     * } catch (Exception e) {
     *     // Handle exception.
     *     throw AutoCloseables.closeQuietlySuppress(autoCloseable, e);
     * }
     * </pre>
     * <p>
     * Also consider using a try-with-resources statement where appropriate.
     * </p>
     *
     * @param <T>       The Throwable type.
     * @param closeable The object to close, may be null or already closed.
     * @param throwable Add the exception throw by the closeable to the given Throwable.
     * @return The given Throwable.
     * @see Throwable#addSuppressed(Throwable)
     */
    public static <T extends Throwable> T closeQuietlySuppress(final Closeable closeable, final T throwable) {
        closeQuietly(closeable, throwable::addSuppressed);
        return throwable;
    }

    /**
     * No instances needed.
     */
    private AutoCloseables() {
        // empty
    }
}