Lambda表达式实现对list集合的排序,代替Collections.sort(关于comparator(函数式接口) 和 comparable的一些源码介绍)

           以前对List集合进行排序的时候都用Collections类的sort方法,  在jdk1.8出来后就常用Lambda表达式来实现对list集合的排序

   Lambda表达式的介绍如下:

          “Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。

           通俗的来讲就是匿名函数,函数式编程,这也是jdk1.8最大的变化,用Lambda语法来替换以前的匿名内部类,代码量会减少很多看起来也更整洁。

 先介绍下Collections

        介绍Collections之前先说下跟它名字很接近的一个接口Collection(在jdk1.2的时候就已经存在了),此接口是是一个集合接口,集合类的最顶级接口,提供了集合对象进行操作的通用性方法(图一),Collection接口在java类库中有很多实现,直接继承与此接口的有List和Set接口(图二,图四),另外,此Collection还继承Iterable接口(图三),Iterable接口是用来对集合进行迭代的(通常我们遍历集合的时候为了效率都采用迭代器而不用foreach之类进行遍历,此接口是在jdk1.5的时候专门增加的)

 

图一

 

图二:

 

图三:

 

图四:

   

       现在说下Collections是实现Collection接口的集合类的工具类或者帮助类(图5),可以看到此类在jdk1.2的时候已经存在,并且无参构造是私有的,表明此类不允许实例化,并且提供了一系列静态方法供外部调用以实现对集合排序、搜索等操作

 图5:

 

  现在就通过Collections类中的sort方法实现对集合的排序:

  场景是这样的:

        下拉框 “来源” 里面的信息是动态获取的(例图1),从字典表“t_resource_dic”中获取,如果有返回信息的话加上“全部”,如果没有返回信息的话,就不加上“全部”,所以需要在从库里获取信息后才能确定是否加上“全部”,有两种方式可以实现,要么在后端造一个“全部”的一条数据,要么是在前端造“全部”的一条数据,而我选择通过后端实现从小到大的顺序(代码2),在ResourceDic类造一条数据,id设置为0,但此时 resourceDicList.add()新造的这条数据位于最末尾,需要排序到第一位。

        我要对  ResourceDic类(代码1)按照id进行排序(前端展示的时候从0开始),那么我首先想到了Collections工具类的sort方法,第一个参数是List集合,第二个参数需要实现一个比较器 Comparator(英文:n 名词,比较仪)接口,采用匿名内部类的方式实现,完成从小到大的排序。但是通过查看Collections的源码发现有两个重载sort方法入参不同(源码1),只有一个入参的sort方法需要让集合中的泛型类实现Comparable接口,并重写ComparaTo方法。

       下面着重介绍下Comparator和Comparable两个接口的用法和不同:

        往下看:

   

例图1

   --代码1--

package com.chehejia.cms.web.model;

import java.io.Serializable;
import lombok.*;

@Getter 
@Setter
public class ResourceDic implements Serializable {
    private Long id;

    private String resourceName;

    private Integer resourceType;

    private Integer dicType;

    private String dicName;

	public ResourceDic() {
	}

	public ResourceDic(Long id, String resourceName, Integer resourceType) {
		this.id = id;
		this.resourceName = resourceName;
		this.resourceType = resourceType;
	}

	private static final long serialVersionUID = 1L;
}

  代码2

/**
	 * 获取优惠来源
	 * @return
	 */
	@Override
	public Result<Object> getSourceList() {
		List<ResourceDic> resourceDicList  = this.resourceDicMapper.getSourceList(BaseEnums.RESOURCE_MEMBER_DIC_TYPE.getCode());
		if (!CollectionUtils.isEmpty(resourceDicList)) {
			resourceDicList.add(new ResourceDic(Integer.toUnsignedLong(BaseEnums.ALL_ROURCE.getCode()),BaseEnums.ALL_ROURCE.getDesc(),BaseEnums.ALL_ROURCE.getCode()));
			Collections.sort(resourceDicList, new Comparator<ResourceDic>() {
				@Override
				public int compare(ResourceDic o1, ResourceDic o2) {
					/** 从小到大的顺序 */
				    return 	o1.getId().compareTo(o2.getId());
				}
			});
		}
		log.info("service层获取优惠来源, 结果:  resourceDicList = {}",resourceDicList);
		return Results.success(resourceDicList);
	}

 

 

  源码1

   @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }

    /**
     * Sorts the specified list according to the order induced by the
     * specified comparator.  All elements in the list must be <i>mutually
     * comparable</i> using the specified comparator (that is,
     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
     * for any elements {@code e1} and {@code e2} in the list).
     *
     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
     * not be reordered as a result of the sort.
     *
     * <p>The specified list must be modifiable, but need not be resizable.
     *
     * @implNote
     * This implementation defers to the {@link List#sort(Comparator)}
     * method using the specified list and comparator.
     *
     * @param  <T> the class of the objects in the list
     * @param  list the list to be sorted.
     * @param  c the comparator to determine the order of the list.  A
     *        {@code null} value indicates that the elements' <i>natural
     *        ordering</i> should be used.
     * @throws ClassCastException if the list contains elements that are not
     *         <i>mutually comparable</i> using the specified comparator.
     * @throws UnsupportedOperationException if the specified list's
     *         list-iterator does not support the {@code set} operation.
     * @throws IllegalArgumentException (optional) if the comparator is
     *         found to violate the {@link Comparator} contract
     * @see List#sort(Comparator)
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

        Comparator和Comparable接口都是实现排序的

        首先,  先看Comparator,英文的意思为:“n. [仪] 比较仪;比测仪”,很明显这是个名词,哈哈,根据英文的语法内涵,此接口用匿名内部类的方式实现排序最合适(“比较器”拿来直接用),事实证明学好英文对深入编程是很重要的,看源码2知道此接口也是jdk1.2的时候增加的(@FunctionalInterface注解是jdk1.8增加的,变成了函数形式接口--这意味着后面的代码用Lambda表达式来实现排序可以用到Comparator接口,1.8重要的改变就是函数式编程(源码3))。

       所以,只要实现@FunctionalInterface注解的接口都是函数式接口,都可以用Lambda表达式来实现操作,是代码变得更简洁,

       其次, Comparable,英文的意思为:“adj. 可比较的;比得上的”,很明显这是个形容词,再哈哈,根据英文的语法内涵,“可比较的”修饰为名词后再拿来用,那么用实体类来实现Comparable这个接口,完成“修饰的”是最合适。此接口是jdk1.2增加的(源码4),并且只有一个方法 compareTo,注意此接口上没有@FunctionalInterface注解,所以此接口不是函数式接口,后续的博客我会专门针对jdk1.8的新功能做讲解

       接下来我的 ResourceDic类实现了Comparable接口(代码3),并重写了compareTo方法,实现对id的从小到大排序,在service层只需用Collections类的一个入参的sort方法(代码4

      接下来讲下用jdk1.8新增的Lambda表达式实现排序,用函数式编程来完成。

      List接口在jdk1.8中新增了一个sort方法(图6),入参为 Comparator 接口的对象,实现代码(代码5),只需要通过 resourceDicList.sort((r1, r2) -> r1.getId().compareTo(r2.getId())); 这一行代码就可以实现,瞬间就变得很简洁,但是刚用 函数式  编程会感觉很不习惯,没关系,先学会用,慢慢就会领悟到。

      实际上Lambda中的λ表达式本质上是一个匿名方法,λ表达式有三部分组成:参数列表,箭头(->),以及一个表达式或语句块。如“resourceDicList.sort((r1, r2) -> r1.getId().compareTo(r2.getId()));”r1和r2是参数列表,箭头 ->,r1.getId().compareTo(r2.getId())是语句块。其中表达式执行后会返回结果, 语句块中的语句会被依次的执行,和普通方法中的语句是一样的效果。

     先写到这里了,总之jdk1.8的Lambda表达式的函数式编程是个非常有趣的东西,值得我们去深入研究并予以熟练应用,如果不懂不熟练应用1.8新增的功能,可能会被淘汰调的, 哈哈, 周末专门写这篇文章,周末愉快。

    

    源码2

 *
 * @author  Josh Bloch
 * @author  Neal Gafter
 * @see Comparable
 * @see java.io.Serializable
 * @since 1.2
 */
@FunctionalInterface
public interface Comparator<T> {
    /**
     * 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.<p>
     *
     * In the foregoing description, the notation
     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
     * <i>expression</i> is negative, zero or positive.<p>
     *
     * The implementor must ensure that <tt>sgn(compare(x, y)) ==
     * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
     * implies that <tt>compare(x, y)</tt> must throw an exception if and only
     * if <tt>compare(y, x)</tt> throws an exception.)<p>
     *
     * The implementor must also ensure that the relation is transitive:
     * <tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
     * <tt>compare(x, z)&gt;0</tt>.<p>
     *
     * Finally, the implementor must ensure that <tt>compare(x, y)==0</tt>
     * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
     * <tt>z</tt>.<p>
     *
     * It is generally the case, but <i>not</i> strictly required that
     * <tt>(compare(x, y)==0) == (x.equals(y))</tt>.  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.
     */
    int compare(T o1, T o2);

    /**
     * Indicates whether some other object is &quot;equal to&quot; this
     * comparator.  This method must obey the general contract of
     * {@link Object#equals(Object)}.  Additionally, this method can return
     * <tt>true</tt> <i>only</i> if the specified object is also a comparator
     * and it imposes the same ordering as this comparator.  Thus,
     * <code>comp1.equals(comp2)</code> implies that <tt>sgn(comp1.compare(o1,
     * o2))==sgn(comp2.compare(o1, o2))</tt> for every object reference
     * <tt>o1</tt> and <tt>o2</tt>.<p>
     *
     * Note that it is <i>always</i> safe <i>not</i> to override
     * <tt>Object.equals(Object)</tt>.  However, overriding this method may,
     * in some cases, improve performance by allowing programs to determine
     * that two distinct comparators impose the same order.
     *
     * @param   obj   the reference object with which to compare.
     * @return  <code>true</code> only if the specified object is also
     *          a comparator and it imposes the same ordering as this
     *          comparator.
     * @see Object#equals(Object)
     * @see Object#hashCode()
     */
    boolean equals(Object obj);

  源码3:

 *
 * @jls 4.3.2. The Class Object
 * @jls 9.8 Functional Interfaces
 * @jls 9.4.3 Interface Method Body
 * @since 1.8
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

  源码4:

 * @param <T> the type of objects that this object may be compared to
 *
 * @author  Josh Bloch
 * @see java.util.Comparator
 * @since 1.2
 */
public interface Comparable<T> {
    /**
     * Compares this object with the specified object for order.  Returns a
     * negative integer, zero, or a positive integer as this object is less
     * than, equal to, or greater than the specified object.
     *
     * <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
     * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
     * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
     * <tt>y.compareTo(x)</tt> throws an exception.)
     *
     * <p>The implementor must also ensure that the relation is transitive:
     * <tt>(x.compareTo(y)&gt;0 &amp;&amp; y.compareTo(z)&gt;0)</tt> implies
     * <tt>x.compareTo(z)&gt;0</tt>.
     *
     * <p>Finally, the implementor must ensure that <tt>x.compareTo(y)==0</tt>
     * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
     * all <tt>z</tt>.
     *
     * <p>It is strongly recommended, but <i>not</i> strictly required that
     * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>.  Generally speaking, any
     * class that implements the <tt>Comparable</tt> interface and violates
     * this condition should clearly indicate this fact.  The recommended
     * language is "Note: this class has a natural ordering that is
     * inconsistent with equals."
     *
     * <p>In the foregoing description, the notation
     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
     * <i>expression</i> is negative, zero or positive.
     *
     * @param   o the object to be compared.
     * @return  a negative integer, zero, or a positive integer as this object
     *          is less than, equal to, or greater than the specified object.
     *
     * @throws NullPointerException if the specified object is null
     * @throws ClassCastException if the specified object's type prevents it
     *         from being compared to this object.
     */
    public int compareTo(T o);
}

  代码3:

package com.chehejia.cms.web.model;


import java.io.Serializable;
import lombok.*;

@Getter 
@Setter
public class ResourceDic implements Serializable, Comparable<ResourceDic> {
    private Long id;

    private String resourceName;

    private Integer resourceType;

    private Integer dicType;

    private String dicName;


	@Override
	public int compareTo(ResourceDic o) {
       return  this.getId().compareTo(o.getId());
	}

	public ResourceDic() {
	}

	public ResourceDic(Long id, String resourceName, Integer resourceType) {
		this.id = id;
		this.resourceName = resourceName;
		this.resourceType = resourceType;
	}

	private static final long serialVersionUID = 1L;
}

  代码4:

/**
	 * 获取优惠来源
	 * @return
	 */
	@Override
	public Result<Object> getSourceList() {
		List<ResourceDic> resourceDicList  = this.resourceDicMapper.getSourceList(BaseEnums.RESOURCE_MEMBER_DIC_TYPE.getCode());
		if (!CollectionUtils.isEmpty(resourceDicList)) {
			resourceDicList.add(new ResourceDic(Integer.toUnsignedLong(BaseEnums.ALL_ROURCE.getCode()),BaseEnums.ALL_ROURCE.getDesc(),BaseEnums.ALL_ROURCE.getCode()));
			Collections.sort(resourceDicList);
		}
		log.info("service层获取优惠来源, 结果:  resourceDicList = {}",resourceDicList);
		return Results.success(resourceDicList);
	}

图6:

  代码5:

	/**
	 * 获取优惠来源
	 * @return
	 */
	@Override
	public Result<Object> getSourceList() {
		List<ResourceDic> resourceDicList  = this.resourceDicMapper.getSourceList(BaseEnums.RESOURCE_MEMBER_DIC_TYPE.getCode());
		if (!CollectionUtils.isEmpty(resourceDicList)) {
			resourceDicList.add(new ResourceDic(Integer.toUnsignedLong(BaseEnums.ALL_ROURCE.getCode()),BaseEnums.ALL_ROURCE.getDesc(),BaseEnums.ALL_ROURCE.getCode()));
			resourceDicList.sort((r1, r2) -> r1.getId().compareTo(r2.getId()));
		}
		log.info("service层获取优惠来源, 结果:  resourceDicList = {}",resourceDicList);
		return Results.success(resourceDicList);
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值