001/*
002 *  Copyright 2016 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.core.util;
017
018import java.util.function.Consumer;
019import java.util.function.Function;
020import java.util.function.Predicate;
021
022/**
023 * Helper for lambda expressions.
024 */
025public final class LambdaUtils
026{
027    private LambdaUtils()
028    {
029        // empty constructor
030    }
031    
032    /**
033     * Function allowed to throw checked {@link Exception}. <br>
034     * It allows to build one-line lambda for methods throwing checked exceptions.
035     * @param <T> the type of the input to the function.
036     * @param <R> the type of the result of the function.
037     */
038    @FunctionalInterface
039    public interface ThrowingFunction<T, R>
040    {
041        /**
042         * Applies this function to the given argument.
043         * @param t the function argument
044         * @return the function result
045         * @throws Exception if something wrong occurs.
046         */
047        R apply(T t) throws Exception;
048    }
049    
050    /**
051     * Wraps a {@link Function} by catching its {@link Exception} and rethrowing them as {@link RuntimeException}.
052     * @param function the {@link Function} to wrap.
053     * @param <T> The type of input to the function
054     * @param <R> The type of result of the function
055     * @return the wrapped {@link Function}.
056     */
057    public static <T, R> Function<T, R> wrap(ThrowingFunction<T, R> function)
058    {
059        return value -> 
060        {
061            try
062            {
063                return function.apply(value);
064            }
065            catch (Exception e)
066            {
067                if (e instanceof RuntimeException)
068                {
069                    throw (RuntimeException) e;
070                }
071                
072                throw new RuntimeException(e);
073            }
074        };
075    }
076    
077    /**
078     * Predicate allowed to throw checked {@link Exception}. <br>
079     * It allows to build one-line lambda for methods throwing checked exceptions.
080     * @param <T> the type of the input to the predicate.
081     */
082    @FunctionalInterface
083    public interface ThrowingPredicate<T>
084    {
085        /**
086         * Evaluates this predicate on the given argument.
087         * @param t the input argument
088         * @return {@code true} if the input argument matches the predicate,
089         * otherwise {@code false}
090         * @throws Exception if something wrong occurs.
091         */
092        boolean test(T t) throws Exception;
093    }
094    
095    /**
096     * Wraps a {@link Predicate} by catching its {@link Exception} and rethrowing them as {@link RuntimeException}.
097     * @param predicate the {@link Predicate} to wrap.
098     * @param <T> the type of the input to the predicate
099     * @return the wrapped {@link Predicate}.
100     */
101    public static <T> Predicate<T> wrapPredicate(ThrowingPredicate<T> predicate)
102    {
103        return LambdaUtils.wrap(predicate::test)::apply;
104        
105    }
106    
107    /**
108     * Consumer allowed to throw checked {@link Exception}. <br>
109     * It allows to build one-line lambda for methods throwing checked exceptions.
110     * @param <T> the type of the input to the operation
111     */
112    @FunctionalInterface
113    public interface ThrowingConsumer<T>
114    {
115        /**
116         * Performs this operation on the given argument.
117         * @param t the input argument
118         * @throws Exception if something wrong occurs.
119         */
120        void accept(T t) throws Exception;
121    }
122    
123    /**
124     * Wraps a {@link Consumer} by catching its {@link Exception} and rethrowing them as {@link RuntimeException}.
125     * @param consumer the {@link Consumer} to wrap.
126     * @param <T> The type of input to the operation
127     * @return the wrapped {@link Consumer}.
128     */
129    public static <T> Consumer<T> wrapConsumer(ThrowingConsumer<T> consumer)
130    {
131        return value -> 
132        {
133            try
134            {
135                consumer.accept(value);
136            }
137            catch (Exception e)
138            {
139                if (e instanceof RuntimeException)
140                {
141                    throw (RuntimeException) e;
142                }
143                
144                throw new RuntimeException(e);
145            }
146        };
147    }
148}