All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.suppierk.java.util.ThrowableComparator Maven / Gradle / Ivy

Go to download

Java 11 compatible extensions allowing to use checked exceptions in functional programming APIs + Try interface

There is a newer version: 2.0.0
Show newest version
/*
 * MIT License
 *
 * Copyright (c) 2020 Roman Khlebnov
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package io.github.suppierk.java.util;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 * A comparison function, which imposes a total ordering on some collection of objects.
 * Comparators can be passed to a sort method (such as {@link Collections#sort(List, Comparator)
 * Collections.sort} or {@link Arrays#sort(Object[], Comparator) Arrays.sort}) to allow precise
 * control over the sort order. Comparators can also be used to control the order of certain data
 * structures (such as {@link SortedSet sorted sets} or {@link SortedMap sorted maps}), or to
 * provide an ordering for collections of objects that don't have a {@link Comparable natural
 * ordering}.
 *
 * 

The ordering imposed by a comparator {@code c} on a set of elements {@code S} is said to be * consistent with equals if and only if {@code c.compare(e1, e2)==0} has the same boolean * value as {@code e1.equals(e2)} for every {@code e1} and {@code e2} in {@code S}. * *

Caution should be exercised when using a comparator capable of imposing an ordering * inconsistent with equals to order a sorted set (or sorted map). Suppose a sorted set (or sorted * map) with an explicit comparator {@code c} is used with elements (or keys) drawn from a set * {@code S}. If the ordering imposed by {@code c} on {@code S} is inconsistent with equals, the * sorted set (or sorted map) will behave "strangely." In particular the sorted set (or sorted map) * will violate the general contract for set (or map), which is defined in terms of {@code equals}. * *

For example, suppose one adds two elements {@code a} and {@code b} such that {@code * (a.equals(b) && c.compare(a, b) != 0)} to an empty {@code TreeSet} with comparator {@code c}. The * second {@code add} operation will return true (and the size of the tree set will increase) * because {@code a} and {@code b} are not equivalent from the tree set's perspective, even though * this is contrary to the specification of the {@link Set#add Set.add} method. * *

Note: It is generally a good idea for comparators to also implement {@code * java.io.Serializable}, as they may be used as ordering methods in serializable data structures * (like {@link TreeSet}, {@link TreeMap}). In order for the data structure to serialize * successfully, the comparator (if provided) must implement {@code Serializable}. * *

For the mathematically inclined, the relation that defines the imposed ordering * that a given comparator {@code c} imposes on a given set of objects {@code S} is: * *

 *       {(x, y) such that c.compare(x, y) <= 0}.
 * 
* * The quotient for this total order is: * *
 *       {(x, y) such that c.compare(x, y) == 0}.
 * 
* *

It follows immediately from the contract for {@code compare} that the quotient is an * equivalence relation on {@code S}, and that the imposed ordering is a total order * on {@code S}. When we say that the ordering imposed by {@code c} on {@code S} is consistent * with equals, we mean that the quotient for the ordering is the equivalence relation defined * by the objects' {@link Object#equals(Object) equals(Object)} method(s): * *

 *     {(x, y) such that x.equals(y)}. 
* *

Unlike {@code Comparable}, a comparator may optionally permit comparison of null arguments, * while maintaining the requirements for an equivalence relation. * *

Permits checked exceptions unlike {@link Comparator} * *

This interface is a member of the Java Collections Framework. * * @param the type of objects that may be compared by this comparator * @see Comparable * @see java.io.Serializable */ @FunctionalInterface @SuppressWarnings("squid:S112") public interface ThrowableComparator extends Comparator { /** * Compares its two arguments for order. Returns a negative integer, zero, or a positive integer * as the first argument is less than, equal to, or greater than the second. * *

In the foregoing description, the notation {@code sgn(}expression{@code )} designates * the mathematical signum function, which is defined to return one of {@code -1}, {@code * 0}, or {@code 1} according to whether the value of expression is negative, zero or * positive. * *

The implementor must ensure that {@code sgn(compare(x, y)) == -sgn(compare(y, x))} for all * {@code x} and {@code y}. (This implies that {@code compare(x, y)} must throw an exception if * and only if {@code compare(y, x)} throws an exception.) * *

The implementor must also ensure that the relation is transitive: {@code ((compare(x, * y)>0) && (compare(y, z)>0))} implies {@code compare(x, z)>0}. * *

Finally, the implementor must ensure that {@code compare(x, y)==0} implies that {@code * sgn(compare(x, z))==sgn(compare(y, z))} for all {@code z}. * *

It is generally the case, but not strictly required that {@code (compare(x, y)==0) == * (x.equals(y))}. Generally speaking, any comparator that violates this condition should clearly * indicate this fact. The recommended language is "Note: this comparator imposes orderings that * are inconsistent with equals." * * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @return a negative integer, zero, or a positive integer as the first argument is less than, * equal to, or greater than the second. * @throws NullPointerException if an argument is null and this comparator does not permit null * arguments * @throws ClassCastException if the arguments' types prevent them from being compared by this * comparator. * @throws Throwable occurred during processing */ int compareUnsafe(T o1, T o2) throws Throwable; /** * Compares its two arguments for order. Returns a negative integer, zero, or a positive integer * as the first argument is less than, equal to, or greater than the second. * *

In the foregoing description, the notation {@code sgn(}expression{@code )} designates * the mathematical signum function, which is defined to return one of {@code -1}, {@code * 0}, or {@code 1} according to whether the value of expression is negative, zero or * positive. * *

The implementor must ensure that {@code sgn(compare(x, y)) == -sgn(compare(y, x))} for all * {@code x} and {@code y}. (This implies that {@code compare(x, y)} must throw an exception if * and only if {@code compare(y, x)} throws an exception.) * *

The implementor must also ensure that the relation is transitive: {@code ((compare(x, * y)>0) && (compare(y, z)>0))} implies {@code compare(x, z)>0}. * *

Finally, the implementor must ensure that {@code compare(x, y)==0} implies that {@code * sgn(compare(x, z))==sgn(compare(y, z))} for all {@code z}. * *

It is generally the case, but not strictly required that {@code (compare(x, y)==0) == * (x.equals(y))}. Generally speaking, any comparator that violates this condition should clearly * indicate this fact. The recommended language is "Note: this comparator imposes orderings that * are inconsistent with equals." * * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @return a negative integer, zero, or a positive integer as the first argument is less than, * equal to, or greater than the second. * @throws NullPointerException if an argument is null and this comparator does not permit null * arguments * @throws ClassCastException if the arguments' types prevent them from being compared by this * comparator. */ @Override default int compare(T o1, T o2) { try { return compareUnsafe(o1, o2); } catch (Throwable throwable) { return ExceptionSuppressor.asUnchecked(throwable); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy