问题描述
public List< Comparator< Entity>> sort(Map< String,String> map){
List< Comparator< Entity>> list = new ArrayList< Comparator< Entity>>(); (Map.Entry< String,String> entry:map.entrySet()){
boolean sortOrder = entry.getValue()。equalsIgnoreCase(asc);
switch(entry.getKey()){
caseid:
list.add(sortOrder?Comparator.comparing(Entity :: getId):Comparator.comparing Entity :: getId,Comparator.reverseOrder()));
休息;
casesize:
list.add(sortOrder?Comparator.comparing(Entity :: getSize):Comparator.comparing(Entity :: getSize,Comparator.reverseOrder()));
// break;
}
}
返回列表;
}
上述方法返回的列表的使用方式如下。 / p>
// map是根据客户端与排序的交互进行初始化的。
包含两个类型为
//基于客户端的交互,地图可能是空的,或者它可能包含一个或多个排序字段。
if(MapUtils.isNotEmpty(map)){// map = new LinkedHashMap< String,String>();
List< Comparator< Entity>>比较器=排序(地图);
比较器< Entity> comparator = comparators.remove(0); (比较器<实体> c:比较器)
{
比较器= comparator.thenComparing(c);
list = list.stream()。sorted(comparator).collect(Collectors.toList());
} else {
//这是默认排序。
list = list.stream()。sorted(Comparator.comparing(Entity :: getId).reversed())。collect(Collectors.toList());
code
$ b $实体Integer
和大小
的类型为id
code> BigDecimal 和list
是一种List< Entity>
。
由于有几个其他类具有相同数据类型的相同字段,我希望这个方法是通用的,因此它必须像这样定义一次, / p>
public< T extends Object>列表与LT;比较< T>> (Map< String,String> map,Class< T> clazz){
List< Comparator< T>> list = new ArrayList< Comparator< T>>();
//排序逻辑。
返回列表;
}
但是这样做,像
T :: getId因为泛型类型参数
/ p>T
的计算结果为Object
。
有没有一种在不知道实际类类型的情况下对代码进行排序的方法,以便在需要时防止此方法在任何地方重复?
解决方案一种简单的方法,无需依赖反射魔术,就可以为所有具有相同数据类型的字段引入一个通用接口,
实体
。
考虑以下
IdSize
实体
。接口IdSize {
Integer getId( );
BigDecimal getSize();
}
类实体实现IdSize {
private Integer id;
私人BigDecimal大小;
@Override
public Integer getId(){
return id;
}
@Override
public BigDecimal getSize(){
return size;
}
}
然后你可以使你的方法成为通用的像这样:
public< T extends IdSize>列表与LT;比较< T>> sort(Map< String,String> map){
List< Comparator< T>> list = new ArrayList< Comparator< T>>(); (Map.Entry< String,String> entry:map.entrySet()){
boolean sortOrder = entry.getValue()。equalsIgnoreCase(asc);
比较器< T> comparator = null;
switch(entry.getKey()){
caseid:
comparator = Comparator.comparing(IdSize :: getId);
休息;
casesize:
comparator = Comparator.comparing(IdSize :: getSize);
休息;
default://在这里做些什么,抛出异常?
}
list.add(sortOrder?comparator:comparator.reversed());
}
返回列表;
}
(我重构了一些switch-case语句来删除重复的代码。 )。另外,您可能需要添加一个默认子句。
The following method performs ordering.
public List<Comparator<Entity>> sort(Map<String, String> map) { List<Comparator<Entity>> list = new ArrayList<Comparator<Entity>>(); for (Map.Entry<String, String> entry : map.entrySet()) { boolean sortOrder = entry.getValue().equalsIgnoreCase("asc"); switch (entry.getKey()) { case "id": list.add(sortOrder ? Comparator.comparing(Entity::getId) : Comparator.comparing(Entity::getId, Comparator.reverseOrder())); break; case "size": list.add(sortOrder ? Comparator.comparing(Entity::getSize) : Comparator.comparing(Entity::getSize, Comparator.reverseOrder())); //break; } } return list; }
The list being returned by the above method is used in the following way.
// map is initialized somewhere based on client's interactions with sorting. // Based on client's interactions, map may be empty or it may contain one or more ordering fields. if (MapUtils.isNotEmpty(map)) { // map = new LinkedHashMap<String, String>(); List<Comparator<Entity>> comparators = sort(map); Comparator<Entity> comparator = comparators.remove(0); for (Comparator<Entity> c : comparators) { comparator = comparator.thenComparing(c); } list = list.stream().sorted(comparator).collect(Collectors.toList()); } else { // This is the default ordering. list = list.stream().sorted(Comparator.comparing(Entity::getId).reversed()).collect(Collectors.toList()); }
Entity
contains two fields namedid
of typeInteger
andsize
of typeBigDecimal
andlist
is a type ofList<Entity>
.Since there are several other classes having the same fields with the same datatypes, I want this method to be generic so that it has to be defined only once like so,
public <T extends Object> List<Comparator<T>> sort(Map<String, String> map, Class<T> clazz) { List<Comparator<T>> list = new ArrayList<Comparator<T>>(); // Sorting logic. return list; }
But doing so, expressions like
T::getId
will not compile as obvious, since the generic type parameterT
evaluates toObject
.Is there a way to code sorting without knowing the actual class type so that this method can be prevented from being repeated everywhere, when it is needed?
解决方案A simple way, without having to rely on reflection magic, is to introduce a common interface for all the types having the same fields with the same datatypes as
Entity
.Consider the following
IdSize
interface with the followingEntity
.interface IdSize { Integer getId(); BigDecimal getSize(); } class Entity implements IdSize { private Integer id; private BigDecimal size; @Override public Integer getId() { return id; } @Override public BigDecimal getSize() { return size; } }
Then you can make your method generic like this:
public <T extends IdSize> List<Comparator<T>> sort(Map<String, String> map) { List<Comparator<T>> list = new ArrayList<Comparator<T>>(); for (Map.Entry<String, String> entry : map.entrySet()) { boolean sortOrder = entry.getValue().equalsIgnoreCase("asc"); Comparator<T> comparator = null; switch (entry.getKey()) { case "id": comparator = Comparator.comparing(IdSize::getId); break; case "size": comparator = Comparator.comparing(IdSize::getSize); break; default: // do something here, throw an exception? } list.add(sortOrder ? comparator : comparator.reversed()); } return list; }
(I refactored a little the switch-case statement to remove the duplicated code.). Also, you might want to add a default clause.
这篇关于在Java 8中对通用方法中的集合进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!