com.feilong.core.util.SortUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.feilong.core.util.SortUtil.java

Source

/*
 * Copyright (C) 2008 feilong
 *
 * Licensed 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
 *
 *         http://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 com.feilong.core.util;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.collections4.comparators.ReverseComparator;
import org.apache.commons.lang3.Validate;

import com.feilong.core.util.comparator.BeanComparatorUtil;
import com.feilong.core.util.comparator.PropertyComparator;

import static com.feilong.core.bean.ConvertUtil.toArray;
import static com.feilong.core.bean.ConvertUtil.toList;
import static com.feilong.core.bean.ConvertUtil.toMap;

/**
 * ?.
 * 
 * <h3>:</h3>
 * <blockquote>
 * <ol>
 * <li>?,jdk?sort,
 * 
 * <pre class="code">
 * {@link java.util.Arrays#sort(Object[])}
 * </pre>
 * 
 * 
 * 
 * <pre class="code">
 * {@link java.util.Collections#sort(List)}
 * </pre>
 * 
 *   void,?23?
 * 
 * </li>
 * <li>,bean list???</li>
 * </ol>
 * </blockquote>
 *
 * @author <a href="http://feitianbenyue.iteye.com/">feilong</a>
 * @since 1.8.0
 */
public final class SortUtil {

    /** Don't let anyone instantiate this class. */
    private SortUtil() {
        //AssertionError?. ?????. ???.
        //see Effective Java 2nd
        throw new AssertionError("No " + getClass().getName() + " instances for you!");
    }

    //*****************************************************************************************
    /**
     *   <code>arrays</code> ?.
     * 
     * <h3>????:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * 
     * public static String toSalesPropertiesIdsJson(Long...itemPropertiesIdLongs){
     *     Arrays.sort(itemPropertiesIdLongs);
     *     return JsonUtil.format(itemPropertiesIdLongs, 0, 0);
     * }
     * 
     * </pre>
     * 
     * ???:
     * 
     * <pre class="code">
     * 
     * public static String toSalesPropertiesIdsJson(Long...itemPropertiesIdLongs){
     *     return JsonUtil.format(sort(itemPropertiesIdLongs), 0, 0);
     * }
     * </pre>
     * 
     * <b>?:</b>
     * 
     * <pre class="code">
     * 
     * <span style="color:green">// ,??</span>
     * private Long getDefaultCategoryId(Long[] categoriesIds){
     *     Arrays.sort(categoriesIds);
     *     return categoriesIds[0];
     * }
     * 
     * </pre>
     * 
     * ???:
     * 
     * <pre class="code">
     * 
     * <span style="color:green">// ,??</span>
     * private Long getDefaultCategoryId(Long[] categoriesIds){
     *     return sort(categoriesIds)[0];
     * }
     * </pre>
     * 
     * </blockquote>
     *
     * @param <T>
     *            the generic type
     * @param arrays
     *            the arrays
     * @return  <code>array</code> null, empty array<br>
     * @see java.util.Arrays#sort(Object[])
     */
    @SafeVarargs
    public static <T> T[] sort(T... arrays) {
        if (null == arrays) {
            return toArray();
        }
        Arrays.sort(arrays);
        return arrays;
    }

    /**
     *   <code>arrays</code> <code>comparator</code> ?.
     *
     * @param <T>
     *            the generic type
     * @param arrays
     *            the arrays
     * @param comparator
     *            the comparator
     * @return  <code>array</code> null, empty array<br>
     * @see java.util.Arrays#sort(Object[], Comparator)
     */
    public static <T> T[] sort(T[] arrays, Comparator<? super T> comparator) {
        if (null == arrays) {
            return toArray();
        }
        Arrays.sort(arrays, comparator);
        return arrays;
    }

    //*****************************************************************************************

    /**
     *  ? <code>list</code> ?.
     * 
     * <p>
     * {@link java.util.Collections#sort(List) Collections.sort}  {@link java.util.Arrays#sort(Object[]) Arrays.sort}
     * </p>
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * 
     * List{@code <Integer>} list = toList(5, 10, 3, 2);
     * LOGGER.debug(JsonUtil.format(sort(list), 0, 0));
     * 
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * [2,3,5,10]
     * </pre>
     * 
     * </blockquote>
     *
     * @param <T>
     *            the generic type
     * @param list
     *            the list
     * @return  <code>list</code> null, {@link Collections#emptyList()}<br>
     * @see java.util.Collections#sort(List)
     */
    public static <T extends Comparable<? super T>> List<T> sort(List<T> list) {
        if (null == list) {
            return emptyList();
        }
        Collections.sort(list);
        return list;
    }

    /**
     *  ? <code>list</code>, <code>comparator</code> ?.
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * 
     * List{@code <User>} list = new ArrayList{@code <User>}();
     * list.add(new User(12L, 18));
     * list.add(new User(2L, 36));
     * list.add(new User(5L, 22));
     * list.add(new User(1L, 8));
     * SortUtil.sort(list, new PropertyComparator{@code <User>}("id"));
     * LOGGER.debug(JsonUtil.format(list));
     * 
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * [{
        "id": 1,
        "age": 8
    },
            {
        "id": 2,
        "age": 36
    },
            {
        "id": 5,
        "age": 22
    },
            {
        "id": 12,
        "age": 18
    }]
     * </pre>
     * 
     * ,?:
     * 
     * <pre class="code">
     * SortUtil.sort(list, "id");
     * </pre>
     * 
     * </blockquote>
     *
     * @param <O>
     *            the generic type
     * @param list
     *            the list
     * @param comparator
     *            the comparator
     * @return  <code>list</code> null, {@link Collections#emptyList()}<br>
     * @see java.util.Collections#sort(List, Comparator)
     */
    public static <O> List<O> sort(List<O> list, Comparator<? super O> comparator) {
        if (null == list) {
            return emptyList();
        }

        Collections.sort(list, comparator);
        return list;
    }

    //*****************************************************************************************

    /**
     *  ? <code>list</code>, <code>propertyName</code> ?.
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * 
     * List{@code <User>} list = toList(//
     *                 new User(12L, 18),
     *                 new User(2L, 36),
     *                 new User(2L, 2),
     *                 new User(2L, 30),
     *                 new User(1L, 8));
     * SortUtil.sort(list, "age");
     * LOGGER.debug(JsonUtil.formatWithIncludes(list, "id", "age"));
     * 
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * [
     * {"id": 2,"age": 2},
     * {"id": 1,"age": 8},
     * {"id": 12,"age": 18}, 
     * {"id": 2,"age": 30},
     * {"id": 2,"age": 36}
     * ]
     * </pre>
     * 
     * </blockquote>
     * 
     * <h3>2:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * User id12 = new User(12L, 18);
     * User id2 = new User(2L, 36);
     * User id5 = new User(5L, 22);
     * User id1 = new User(1L, 8);
     * List<User> list = toList(id12, id2, id5, id1);
     * sort(list, "id");
     * assertThat(list, contains(id1, id2, id5, id12));
     * </pre>
     * 
     * </blockquote>
     *
     * @param <O>
     *            the generic type
     * @param list
     *            the list
     * @param propertyName
     *            O??,Possibly indexed and/or nested name of the property to be modified,??
     *            <a href="../bean/BeanUtil.html#propertyName">propertyName</a>
     * @return  <code>list</code> null, {@link Collections#emptyList()}<br>
     * @throws NullPointerException
     *              <code>propertyNames</code> null
     * @throws IllegalArgumentException
     *              <code>propertyNames</code> empty
     * @see BeanComparatorUtil#propertyComparator(String)
     * @see #sort(List, Comparator)
     */
    public static <O> List<O> sort(List<O> list, String propertyName) {
        if (null == list) {
            return emptyList();
        }
        Validate.notEmpty(propertyName, "propertyName can't be null/empty!");
        return sort(list, BeanComparatorUtil.propertyComparator(propertyName));
    }

    /**
     *  ? <code>list</code>,(?)?.
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * 
     * List{@code <User>} list = new ArrayList{@code <User>}();
     * list.add(new User(12L, 18));
     * list.add(new User(2L, 36));
     * list.add(new User(2L, 2));
     * list.add(new User(2L, 30));
     * list.add(new User(1L, 8));
     * SortUtil.sort(list, "id", "age");
     * LOGGER.debug(JsonUtil.formatWithIncludes(list, "id", "age"));
     * 
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
    [{"id": 1,"age": 8},
    {"id": 2,"age": 2},
    {"id": 2,"age": 30},
    {"id": 2,"age": 36},
    {"id": 12,"age": 18}]
     * </pre>
     * 
     * </blockquote>
     *
     * @param <O>
     *            the generic type
     * @param list
     *            the list
     * @param propertyNames
     *            O??,Possibly indexed and/or nested name of the property to be modified,??
     *            <a href="../bean/BeanUtil.html#propertyName">propertyName</a>
     * @return  <code>list</code> null, {@link Collections#emptyList()}<br>
     * @throws NullPointerException
     *              <code>propertyNames</code> null
     * @throws IllegalArgumentException
     *              <code>propertyNames</code> empty , null
     * @see BeanComparatorUtil#chainedComparator(String...)
     * @see org.apache.commons.collections4.ComparatorUtils#chainedComparator(java.util.Comparator...)
     * @see #sort(List, Comparator)
     */
    public static <O> List<O> sort(List<O> list, String... propertyNames) {
        if (null == list) {
            return emptyList();
        }
        Validate.notEmpty(propertyNames, "propertyNames can't be null/empty!");
        Validate.noNullElements(propertyNames, "propertyName:%s has empty value", propertyNames);

        return sort(list, BeanComparatorUtil.chainedComparator(propertyNames));
    }

    //*************************************************************************************************

    /**
     *  ? <code>list</code>, <code>propertyName</code> ? <code>propertyValues</code> ?.
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * 
     * User zhangfei = new User("", 23);
     * User guanyu = new User("", 30);
     * User liubei = new User("", 25);
     * List{@code <User>} list = toList(zhangfei, guanyu, liubei);
     * 
     * List{@code <User>} select = CollectionsUtil.select(list, "name", "", "");
     * Collections.sort(select, new PropertyComparator{@code <User>}("name", new FixedOrderComparator{@code <>}("", "")));
     * LOGGER.debug(JsonUtil.formatWithIncludes(select, "name", "age"));
     * 
     * </pre>
     * 
     * ?:
     * 
     * <pre class="code">
     * 
     * List{@code <User>} select2 = CollectionsUtil.select(list, "name", "", "");
     * LOGGER.debug(JsonUtil.formatWithIncludes(SortUtil.sortByFixedOrderPropertyValues(select2, "name", "", ""), "name", "age"));
     * 
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
    [{
            "age": 25,
            "name": ""
        },
                {
            "age": 30,
            "name": ""
        }
    ]
     * </pre>
     * 
     * </blockquote>
     *
     * @param <O>
     *            the generic type
     * @param <V>
     *            the value type
     * @param list
     *            the list
     * @param propertyName
     *            O??,Possibly indexed and/or nested name of the property to be modified,??
     *            <a href="../bean/BeanUtil.html#propertyName">propertyName</a>
     * @param propertyValues
     *            the property values
     * @return  <code>list</code> null, {@link Collections#emptyList()}<br>
     * @throws NullPointerException
     *              <code>propertyName</code> null
     * @throws IllegalArgumentException
     *              <code>propertyName</code> blank
     * @see BeanComparatorUtil#propertyComparator(String, Object...)
     * @see #sort(List, Comparator)
     */
    @SafeVarargs
    public static <O, V> List<O> sortByFixedOrderPropertyValues(List<O> list, String propertyName,
            V... propertyValues) {
        if (null == list) {
            return emptyList();
        }
        Validate.notBlank(propertyName, "propertyName can't be blank!");
        return sort(list, BeanComparatorUtil.propertyComparator(propertyName, propertyValues));
    }

    /**
     *  ? <code>list</code>, <code>propertyName</code> ? <code>propertyValues</code> ?.
     *
     * @param <O>
     *            the generic type
     * @param <V>
     *            the value type
     * @param list
     *            the list
     * @param propertyName
     *            O??,Possibly indexed and/or nested name of the property to be modified,??
     *            <a href="../bean/BeanUtil.html#propertyName">propertyName</a>
     * @param propertyValues
     *            the property values
     * @return  <code>list</code> null, {@link Collections#emptyList()}<br>
     * @throws NullPointerException
     *              <code>propertyName</code> null
     * @throws IllegalArgumentException
     *              <code>propertyName</code> blank
     * @see BeanComparatorUtil#propertyComparator(String, List)
     * @see #sort(List, Comparator)
     */
    public static <O, V> List<O> sortByFixedOrderPropertyValues(List<O> list, String propertyName,
            List<V> propertyValues) {
        if (null == list) {
            return emptyList();
        }
        Validate.notBlank(propertyName, "propertyName can't be blank!");
        return sort(list, BeanComparatorUtil.propertyComparator(propertyName, propertyValues));
    }

    //*******************************?****************************************************
    /**
     * key asc??.
     * 
     * <h3>:</h3>
     * <blockquote>
     * 
     * <pre class="code">
     * Map{@code <String, Comparable>} map = new HashMap{@code <String, Comparable>}();
     * 
     * map.put("a", 123);
     * map.put("c", 345);
     * map.put("b", 8);
     * 
     * LOGGER.debug(JsonUtil.format(SortUtil.sortByKeyAsc(map)));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * {
     * "a": 123,
     * "b": 8,
     * "c": 345
     * }
     * </pre>
     * 
     * </blockquote>
     * 
     * <h3>?:</h3>
     * <blockquote>
     * <p>
     * ? {@link java.util.TreeMap#TreeMap(Map)},TreeMap?? keynull, ? <code>map</code>,keynull,
     * {@link NullPointerException}
     * </p>
     * </blockquote>
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @return  <code>map</code> null, {@link Collections#emptyMap()}<br>
     *         ? {@link TreeMap}
     * @see java.util.TreeMap#TreeMap(Map)
     * @since 1.8.0 move from MapUtil
     */
    public static <K, V> Map<K, V> sortByKeyAsc(Map<K, V> map) {
        if (null == map) {
            return emptyMap();
        }
        return new TreeMap<K, V>(map);
    }

    /**
     * key desc ??.
     * 
     * <h3>:</h3>
     * <blockquote>
     * 
     * <pre class="code">
     * Map{@code <String, Comparable>} map = new HashMap{@code <String, Comparable>}();
     * 
     * map.put("a", 123);
     * map.put("c", 345);
     * map.put("b", 8);
     * 
     * LOGGER.debug(JsonUtil.format(SortUtil.sortByKeyDesc(map)));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * {
     * "c": 345,
     * "b": 8,
     * "a": 123
     * }
     * </pre>
     * 
     * </blockquote>
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @return  <code>map</code> null, {@link Collections#emptyMap()}<br>
     * @see ReverseComparator#ReverseComparator(Comparator)
     * @see PropertyComparator#PropertyComparator(String)
     * @see #sort(Map, Comparator)
     * @since 1.8.0 move from MapUtil
     */
    public static <K, V> Map<K, V> sortByKeyDesc(Map<K, V> map) {
        if (null == map) {
            return emptyMap();
        }
        return sort(map, new ReverseComparator<Map.Entry<K, V>>(new PropertyComparator<Map.Entry<K, V>>("key")));
    }

    /**
     * ?value ???(asc).
     * 
     * <h3>:</h3>
     * <blockquote>
     * 
     * <pre class="code">
     * Map{@code <String, Comparable>} map = new HashMap{@code <String, Comparable>}();
     * map.put("a", 123);
     * map.put("c", 345);
     * map.put("b", 8);
     * LOGGER.debug(JsonUtil.format(SortUtil.sortByValueAsc(map)));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * {
     * "b": 8,
     * "a": 123,
     * "c": 345
     * }
     * </pre>
     * 
     * </blockquote>
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @return  <code>map</code> null, {@link Collections#emptyMap()}<br>
     * @see #sort(Map, Comparator)
     * @since 1.8.0 move from MapUtil
     */
    public static <K, V extends Comparable<V>> Map<K, V> sortByValueAsc(Map<K, V> map) {
        if (null == map) {
            return emptyMap();
        }
        return sort(map, new PropertyComparator<Map.Entry<K, V>>("value"));
    }

    /**
     * ?value ???(desc).
     * 
     * <h3>:</h3>
     * <blockquote>
     * 
     * <pre class="code">
     * Map{@code <String, Comparable>} map = new LinkedHashMap{@code <String, Comparable>}();
     * 
     * map.put("a", 123);
     * map.put("c", 345);
     * map.put("b", 8);
     * 
     * LOGGER.debug(JsonUtil.format(SortUtil.sortByValueDesc(map)));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * {
     * "c": 345,
     * "a": 123,
     * "b": 8
     * }
     * </pre>
     * 
     * </blockquote>
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @return  <code>map</code> null, {@link Collections#emptyMap()}<br>
     * @see #sort(Map, Comparator)
     * @since 1.8.0 move from MapUtil
     */
    public static <K, V extends Comparable<V>> Map<K, V> sortByValueDesc(Map<K, V> map) {
        if (null == map) {
            return emptyMap();
        }
        return sort(map, new ReverseComparator<Map.Entry<K, V>>(new PropertyComparator<Map.Entry<K, V>>("value")));
    }

    /**
     *   {@link java.util.Map.Entry Entry}  <code>mapEntryComparator</code> ? <code>map</code>?.
     * 
     * <p>
     * {@link java.util.Map.Entry Entry}?, ?key??,?value??
     * </p>
     * 
     * <h3>:</h3>
     * <blockquote>
     * 
     * map
     * 
     * <pre class="code">
     * Map{@code <String, Integer>} map = new HashMap{@code <String, Integer>}();
     * 
     * map.put("a13", 123);
     * map.put("a2", 345);
     * map.put("a8", 8);
     * </pre>
     * 
     * ? :
     * 
     * <pre class="code">
     * LOGGER.debug(JsonUtil.format(SortUtil.sortByKeyAsc(map)));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * {
     * "a13": 123,
     * "a2": 345,
     * "a8": 8
     * }
     * </pre>
     * 
     * ? a13?,? Comparator,??
     * 
     * <pre class="code">
     * PropertyComparator{@code <Entry<String, Integer>>} propertyComparator = new PropertyComparator{@code <Map.Entry<String, Integer>>}(
     *                 "key",
     *                 new RegexGroupNumberComparator("a(\\d*)"));
     * LOGGER.debug(JsonUtil.format(SortUtil.sort(map, propertyComparator)));
     * </pre>
     * 
     * <b>:</b>
     * 
     * <pre class="code">
     * {
     * "a2": 345,
     * "a8": 8,
     * "a13": 123
     * }
     * </pre>
     * 
     * </blockquote>
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @param mapEntryComparator
     *             {@link java.util.Map.Entry Entry}  {@link Comparator}
     * @return  <code>map</code> null, {@link Collections#emptyMap()}<br>
     *          <code>mapEntryComparator</code> null, {@link NullPointerException}<br>
     * @see java.util.Collections#sort(List, Comparator)
     * @since 1.8.0 move from MapUtil
     */
    public static <K, V> Map<K, V> sort(Map<K, V> map, Comparator<Map.Entry<K, V>> mapEntryComparator) {
        if (null == map) {
            return emptyMap();
        }
        Validate.notNull(mapEntryComparator, "mapEntryComparator can't be null!");

        List<Map.Entry<K, V>> mapEntryList = toList(map.entrySet());
        return toMap(sort(mapEntryList, mapEntryComparator));
    }

}