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 */
017package org.apache.juneau.commons.utils;
018
019import java.util.concurrent.*;
020import java.util.function.*;
021
022/**
023 * Utility methods for composing {@link Predicate} instances.
024 */
025public final class PredicateUtils {
026
027   /**
028    * Consumes the specified value if the predicate is <jk>null</jk> or matches the specified value.
029    *
030    * @param <T> The type being consumed.
031    * @param predicate The predicate.
032    * @param consumer The consumer.
033    * @param value The value.
034    */
035   public static <T> void consumeIf(Predicate<T> predicate, Consumer<T> consumer, T value) {
036      if (test(predicate, value))
037         consumer.accept(value);
038   }
039
040   /**
041    * Returns a function that prints the input value to stderr and returns it unchanged.
042    *
043    * <p>
044    * Useful for debugging streams by inserting into a stream pipeline with {@code .map(peek())}.
045    *
046    * <h5 class='section'>Example:</h5>
047    * <p class='bjava'>
048    *    list.stream()
049    *       .map(peek())
050    *       .filter(x -&gt; x != <jk>null</jk>)
051    *       .collect(Collectors.toList());
052    * </p>
053    *
054    * @param <T> The type of value.
055    * @return A function that prints and returns the value.
056    */
057   public static <T> Function<T,T> peek() {
058      return v -> {
059         System.err.println(v);
060         return v;
061      };
062   }
063
064   /**
065    * Returns a function that prints the input value to stderr using a custom formatter and returns it unchanged.
066    *
067    * <p>
068    * Useful for debugging streams by inserting into a stream pipeline with {@code .map(peek(...))}.
069    *
070    * <h5 class='section'>Example:</h5>
071    * <p class='bjava'>
072    *    list.stream()
073    *       .map(peek(<js>"Processing: {0}"</js>, x -&gt; x.getName()))
074    *       .filter(x -&gt; x != <jk>null</jk>)
075    *       .collect(Collectors.toList());
076    * </p>
077    *
078    * @param <T> The type of value.
079    * @param message A format string using {@code {0}} as placeholder for the formatted value.
080    * @param formatter A function to extract/format the value for display.
081    * @return A function that prints and returns the value.
082    */
083   public static <T> Function<T,T> peek(String message, Function<T,?> formatter) {
084      return v -> {
085         System.err.println(message.replace("{0}", String.valueOf(formatter.apply(v))));
086         return v;
087      };
088   }
089
090   /**
091    * Returns <jk>true</jk> if the specified predicate is <jk>null</jk> or matches the specified value.
092
093    * @param <T> The type being tested.
094    * @param predicate The predicate.
095    * @param value The value to test.
096    * @return <jk>true</jk> if the specified predicate is <jk>null</jk> or matches the specified value.
097    */
098   public static <T> boolean test(Predicate<T> predicate, T value) {
099      return (predicate == null || predicate.test(value));
100   }
101
102   public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
103       var seen = ConcurrentHashMap.newKeySet();
104       return t -> seen.add(keyExtractor.apply(t));
105   }
106
107   private PredicateUtils() {}
108}