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 */
025@SuppressWarnings({
026   "java:S106" // System.err usage is intentional for debug peek() methods
027})
028public final class PredicateUtils {
029
030   /**
031    * Consumes the specified value if the predicate is <jk>null</jk> or matches the specified value.
032    *
033    * @param <T> The type being consumed.
034    * @param predicate The predicate.  Can be <jk>null</jk> (treated as an always-match).
035    * @param consumer The consumer.  Must not be <jk>null</jk> when the predicate matches.
036    * @param value The value.  Can be <jk>null</jk>.
037    */
038   public static <T> void consumeIf(Predicate<T> predicate, Consumer<T> consumer, T value) {
039      if (test(predicate, value))
040         consumer.accept(value);
041   }
042
043   /**
044    * Returns a function that prints the input value to stderr and returns it unchanged.
045    *
046    * @param <T> The type of value.
047    * @return A function that prints and returns the value.
048    */
049   public static <T> Function<T,T> peek() {
050      return v -> {
051         System.err.println(v);
052         return v;
053      };
054   }
055
056   /**
057    * Returns a function that prints the input value to stderr using a custom formatter and returns it unchanged.
058    *
059    * @param <T> The type of value.
060    * @param message A format string using {@code {0}} as placeholder for the formatted value.  Must not be <jk>null</jk>.
061    * @param formatter A function to extract/format the value for display.  Must not be <jk>null</jk>.
062    * @return A function that prints and returns the value.
063    */
064   public static <T> Function<T,T> peek(String message, Function<T,?> formatter) {
065      return v -> {
066         System.err.println(message.replace("{0}", String.valueOf(formatter.apply(v))));
067         return v;
068      };
069   }
070
071   /**
072    * Returns <jk>true</jk> if the specified predicate is <jk>null</jk> or matches the specified value.
073    *
074    * @param <T> The type being tested.
075    * @param predicate The predicate.  Can be <jk>null</jk> (returns <jk>true</jk>).
076    * @param value The value to test.  Can be <jk>null</jk>.
077    * @return <jk>true</jk> if the specified predicate is <jk>null</jk> or matches the specified value.
078    */
079   public static <T> boolean test(Predicate<T> predicate, T value) {
080      return (predicate == null || predicate.test(value));
081   }
082
083   /**
084    * Returns a predicate that filters out duplicate elements based on a key extractor function.
085    *
086    * <p>
087    * This is useful for filtering streams to keep only the first occurrence of each unique key.
088    *
089    * <h5 class='section'>Example:</h5>
090    * <p class='bjava'>
091    *    <jc>// Filter a stream to keep only methods with unique signatures</jc>
092    *    Stream&lt;Method&gt; <jv>methods</jv> = ...;
093    *    Stream&lt;Method&gt; <jv>unique</jv> = <jv>methods</jv>
094    *       .filter(PredicateUtils.<jsm>distinctByKey</jsm>(Method::<jsm>getName</jsm>));
095    * </p>
096    *
097    * @param <T> The element type.
098    * @param keyExtractor A function that extracts the key from each element.  Must not be <jk>null</jk>.
099    * @return A predicate that returns <jk>true</jk> for the first occurrence of each unique key,
100    *    and <jk>false</jk> for subsequent occurrences with the same key.
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}