阅读 138

实现一个通用的中英文排序工具

前言

利用Collator类可以轻松实现排序,但是我们可能有各种model都需要进行排序,这样就会有一个问题,如果单独为每个model写一段排序代码,代码重复量很大。

所以我打算写一个通用的工具,使用泛型+注解+反射的方式来解决。

注解

首先创建注解类

@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.METHOD}) @Documented public @interface SortString { } 复制代码

这个注解的作用就是标识哪个字段或函数是用来排序。

工具类

然后是排序工具类,在我这个工具中排序规则是:中文 > 数字 > 英文,这是我们app的需求,大家可以根据自己的需求进行修改。

完整代码如下

public class SimplifiedChineseSorter {     private static final String SORTINGREGEX = "[^\\p{L}\\p{N}]+|^(The|A|An)\\b";     private static final Collator stringComparator = Collator.getInstance(Locale.SIMPLIFIED_CHINESE);     public static <T> List<T> sortByProvider(List<T> items, SortStringProvider<T> provider, boolean isIgnoreCase) {         if (items == null || items.size() <= 0) {             return null;         }         return sortList(items, provider, isIgnoreCase);     }     public static <T> List<T> sortByFieldName(List<T> items, String fieldName, boolean isIgnoreCase) {         if (items == null || items.size() <= 0) {             return null;         }         Field field = getSortStringField(items.get(0).getClass(), fieldName);         DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(field);         return sortList(items, provider, isIgnoreCase);     }     public static <T> List<T> sortByFieldAnnotation(List<T> items, boolean isIgnoreCase) {         if (items == null || items.size() <= 0) {             return null;         }         Field field = getSortStringField(items.get(0).getClass());         DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(field);         return sortList(items, provider, isIgnoreCase);     }     public static <T> List<T> sortByMethodName(List<T> items, String methodName, boolean isIgnoreCase) {         if (items == null || items.size() <= 0) {             return null;         }         Method method = getSortStringMethod(items.get(0).getClass(), methodName);         DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(method);         return sortList(items, provider, isIgnoreCase);     }     public static <T> List<T> sortByMethodAnnotation(List<T> items, boolean isIgnoreCase) {         if (items == null || items.size() <= 0) {             return null;         }         Method method = getSortStringMethod(items.get(0).getClass());         DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(method);         return sortList(items, provider, isIgnoreCase);     }     private static <T> List<T> sortList(List<T> items, final SortStringProvider<T> provider, final boolean isIgnoreCase) {         if(provider == null){             return items;         }         final List<T> chinieseList = new ArrayList<T>();         final List<T> nonChineseList = new ArrayList<T>();         for (T item : items) {             if (isChineseCharStart(format(provider.getSortString(item), isIgnoreCase))) {                 chinieseList.add(item);             } else {                 nonChineseList.add(item);             }         }         List<T> sortedChineseList = Ordering.from(new Comparator<T>() {             @Override             public int compare(T lhs, T rhs) {                 return stringComparator.compare(format(provider.getSortString(lhs), isIgnoreCase), format(provider.getSortString(rhs), isIgnoreCase));             }         }).sortedCopy(chinieseList);         List<T> sortedNonChineseList = Ordering.from(new Comparator<T>() {             @Override             public int compare(T lhs, T rhs) {                 return format(provider.getSortString(lhs), isIgnoreCase).compareTo(format(provider.getSortString(rhs), isIgnoreCase));             }         }).sortedCopy(nonChineseList);         sortedChineseList.addAll(sortedNonChineseList);         return sortedChineseList;     }     public static <T> Comparator<T> getSortComparatorByProvider(final Class clazz, SortStringProvider<T> provider, boolean isIgnoreCase) {         return getSortComparator(provider, isIgnoreCase);     }     public static <T> Comparator<T> getSortComparatorByFieldName(final Class clazz, final String fieldName, boolean isIgnoreCase) {         Field field = getSortStringField(clazz, fieldName);         DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(field);         return getSortComparator(provider, isIgnoreCase);     }     public static <T> Comparator<T> getSortComparatorByFieldAnnotation(final Class clazz, boolean isIgnoreCase) {         Field field = getSortStringField(clazz);         DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(field);         return getSortComparator(provider, isIgnoreCase);     }     public static <T> Comparator<T> getSortComparatorByMethodName(final Class clazz, final String methodName, boolean isIgnoreCase) {         Method method = getSortStringMethod(clazz, methodName);         DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(method);         return getSortComparator(provider, isIgnoreCase);     }     public static <T> Comparator<T> getSortComparatorByMethodAnnotation(final Class clazz, boolean isIgnoreCase) {         Method method = getSortStringMethod(clazz);         DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(method);         return getSortComparator(provider, isIgnoreCase);     }     private static <T> Comparator<T> getSortComparator(final SortStringProvider<T> provider, final boolean isIgnoreCase) {         return new Comparator<T>() {             @Override             public int compare(final T left, final T right) {                 String leftStr = format(provider.getSortString(left), isIgnoreCase);                 String rightStr = format(provider.getSortString(right), isIgnoreCase);                 if (SimplifiedChineseSorter.isChineseCharStart(leftStr) &&                         SimplifiedChineseSorter.isChineseCharStart(rightStr)) {                     return stringComparator.compare(leftStr, rightStr);                 } else {                     return ComparisonChain.start()                                           .compareTrueFirst(SimplifiedChineseSorter.isChineseCharStart(leftStr),                                                   SimplifiedChineseSorter.isChineseCharStart(rightStr))                                           .compare(leftStr, rightStr, Ordering.natural().nullsFirst())                                           .result();                 }             }         };     }     public static boolean isChineseCharStart(String str) {         return !str.matches("[A-Za-z0-9\"“”]+.*");     }     private static <T> Field getSortStringField(Class<T> tClass) {         Field[] fields = tClass.getDeclaredFields();         if (fields != null) {             for (Field field : fields) {                 if (field.isAnnotationPresent(SortString.class) && field.getType() == String.class) {                     field.setAccessible(true);                     return field;                 }             }         }         Class superClass = tClass.getSuperclass();         if(superClass != null && !superClass.equals(Object.class)){             return getSortStringField(superClass);         }         throw new RuntimeException("The model doesn't have a @SortString field or the type of @SortString field is not a String");     }     private static <T> Field getSortStringField(Class<T> tClass, String sortFieldName) {         Field field = null;         try {             field = tClass.getDeclaredField(sortFieldName);         } catch (NoSuchFieldException e) {         }         finally {             if (field != null && field.getType() == String.class) {                 field.setAccessible(true);                 return field;             }             Class superClass = tClass.getSuperclass();             if(superClass != null && !superClass.equals(Object.class)){                 return getSortStringField(superClass, sortFieldName);             }             throw new RuntimeException("The model doesn't have a field named " + sortFieldName);         }     }     private static <T> Method getSortStringMethod(Class<T> tClass) {         Method[] methods = tClass.getDeclaredMethods();         if (methods != null) {             for (Method method : methods) {                 if (method.isAnnotationPresent(SortString.class) && method.getReturnType() == String.class) {                     method.setAccessible(true);                     return method;                 }             }         }         Class superClass = tClass.getSuperclass();         if(superClass != null && !superClass.equals(Object.class)){             return getSortStringMethod(superClass);         }         throw new RuntimeException("The model doesn't have a @SortString method or the returnning type of @SortString method is not a String");     }     private static <T> Method getSortStringMethod(Class<T> tClass, String sortMethodName) {         Method method = null;         try {             method = tClass.getDeclaredMethod(sortMethodName);         } catch (NoSuchMethodException e) {         }         finally {             if (method != null && method.getReturnType() == String.class) {                 method.setAccessible(true);                 return method;             }             Class superClass = tClass.getSuperclass();             if(superClass != null && !superClass.equals(Object.class)){                 return getSortStringMethod(superClass, sortMethodName);             }             throw new RuntimeException("The model doesn't have a method named " + sortMethodName);         }     }     private static String format(String data, boolean isIgnoreCase) {         Pattern pattern = Pattern.compile(SORTINGREGEX, Pattern.CASE_INSENSITIVE);         if(data == null){             return "";         }         else if(isIgnoreCase){             return pattern.matcher(data.trim()).replaceAll("").toLowerCase();         }         else{             return pattern.matcher(data.trim()).replaceAll("");         }     }     static class DefualtSortStringProvider<T> implements SortStringProvider<T>{         private Object orderBy;         DefualtSortStringProvider(Object orderBy){             this.orderBy = orderBy;         }         public String getSortString(T obj){             try {                 if (orderBy instanceof Field) {                     return (String) ((Field) orderBy).get(obj);                 } else if (orderBy instanceof Method) {                     return (String) ((Method)orderBy).invoke(obj);                 }             }             catch (Exception e){                 Log.e("SimplifiedChineseSorter", "getSortString", e);             }             return "";         }     }     public interface SortStringProvider<T>{         String getSortString(T obj);     } } 复制代码

这个类比较大而全,提供了很多方法来进行排序,其中主要四个函数:

  • sortByFieldName:通过给定的字段名对应的字段进行排序

  • sortByFieldAnnotation:通过带有@SortString的字段进行排序

  • sortByMethodName:通过给定的函数名对应的函数进行排序

  • sortByMethodAnnotation:通过带有@SortString的函数进行排序

其中注意

  1. sortByMethodName要保证该类中没有同名函数,当然也可以加入验证函数参数签名来防止同名函数。

  2. 如果通过注释排序,如果类中有多个@SortString注释,只有第一个有效果。目前这个工具只针对单一维度排序,当然其实完全可以修改成多维度排序,可以增加一个优先级。不过我们需求没有这么复杂,所以就没有进行开发。

使用

使用很简单,只要在类中为那个用来排序的字段(或函数)加上@SortString注解即可,比如

public class Experience {     @SortString     public String name;     public int publicTime;     public String summy;     ... } 复制代码

然后就可以用SimplifiedChineseSorter.sortByFieldAnnotation对Experience列表进行排序即可。

当然也可以用SimplifiedChineseSorter.sortByFieldName,但是相对来说使用注释更加方便易于维护,之所以提供sortByFieldName这类函数,主要是用于一些我们没有权限修改的类(比如三方库中的类),这样就没办法添加注释,就可以通过sortByFieldName这类函数来进行排序,也比较方便。


作者:BennuCTech
链接:https://juejin.cn/post/7033702237344006181


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐