Java Stream排序示例

时间:2020-02-23 14:35:11  来源:igfitidea点击:

在本教程中,我们将看到如何对列表进行排序 Stream.sorted()方法。

Java 8介绍了

Stream.sort()方法可以方便地对元素列表进行排序。
它有助于我们编写简短的函数样式代码而不是样板代码。 java.util.Stream有两个超载版本 sorted()方法。

  • sorted():返回具有自然秩序排序的元素的流
  • sorted(Comparator<? super T> comparator):返回具有由提供的比较器排序的元素的流

如果使用Stream.sorted()方法然后可比较接口,由Integer类实现,将定义整数列表的自然顺序。

让我们了解我们如何使用 Stream.sorted()排序元素列表。

排序整数列表

我们可以简单地使用 sorted()对整数列表进行排序的方法。

List<Integer> result = listOfIntegers.stream()
				                         .sorted()
				                         .collect(Collectors.toList());

其中整数列表由Integer类实现的可比接口排序。

public final class Integer extends Number implements Comparable<Integer> {
....
/**
     * Compares two {@code Integer} objects numerically.
     *
     * @param   anotherInteger   the {@code Integer} to be compared.
     * @return  the value {@code 0} if this {@code Integer} is
     *          equal to the argument {@code Integer}; a value less than
     *          {@code 0} if this {@code Integer} is numerically less
     *          than the argument {@code Integer}; and a value greater
     *          than {@code 0} if this {@code Integer} is numerically
     *           greater than the argument {@code Integer} (signed
     *           comparison).
     * @since   1.2
     */
    public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }
 
    /**
     * Compares two {@code int} values numerically.
     * The value returned is identical to what would be returned by:
     * 
     * Integer.valueOf(x).compareTo(Integer.valueOf(y))
     *
     *
     * @param  x the first {@code int} to compare
     * @param  y the second {@code int} to compare
     * @return the value {@code 0} if {@code x == y};
     *         a value less than {@code 0} if {@code x < y}; and
     *         a value greater than {@code 0} if {@code x > y}
     * @since 1.7
     */
    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

如我们所见,整数在此基础上进行了比较 (x &lt; y) ? -1 : ((x == y) ? 0 : 1)逻辑。

你可以通过 Comparator.reverseOrder()排序方法以反转整数的排序列表。

List<Integer> reverseOrder = listOfIntegers.stream()
				                               .sorted(Comparator.reverseOrder())
				                               .collect(Collectors.toList());

Comparator.reverseOrder()是静态方法,提供了一种对比较器,其强加自然排序。

让我们看看完整的例子来排序整数列表。

package org.igi.theitroad;
 
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
 
public class SortListOfIntegers {
 
	public static void main(String[] args) {
		List<Integer> listOfIntegers = Arrays.asList(new Integer[] {40,34,21,37,20});
		
		List<Integer> result = listOfIntegers.stream()
				                                .sorted()
				                                .collect(Collectors.toList());
		System.out.println(result);
		
		List<Integer> reverseOrder = listOfIntegers.stream()
				                                     .sorted(Comparator.reverseOrder())
				                                     .collect(Collectors.toList());
		System.out.println(reverseOrder);
	}
 
}

排序字符串列表

我们可以简单地使用 sorted()用于对字符串列表进行排序的方法。

List<String> result = listOfStrings.stream()
				                         .sorted()
				                         .collect(Collectors.toList());

其中字符串列表由字符串类实现的可比接口排序。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
....
/**
     * Compares two strings lexicographically.
     *
     * @param   anotherString   the {@code String} to be compared.
     * @return  the value {@code 0} if the argument string is equal to
     *          this string; a value less than {@code 0} if this string
     *          is lexicographically less than the string argument; and a
     *          value greater than {@code 0} if this string is
     *          lexicographically greater than the string argument.
     */
    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
 
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

如我们所见,整数在此基础上进行了比较 (x &lt; y) ? -1 : ((x == y) ? 0 : 1)逻辑。

你可以通过 Comparator.reverseOrder()排序方法以反转整数的排序列表。

List<String> reverseOrder = listOfStrings.stream()
				                               .sorted(Comparator.reverseOrder())
				                               .collect(Collectors.toList());

比较器.ReverseOrder()是静态方法,提供了一个对比较器强加自然排序的反向。

让我们看看完整的例子来排序整数列表。

package org.igi.theitroad;
 
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
 
public class SortListOfStrings {
 
	public static void main(String[] args) {
		List<String> listOfLanguages = Arrays.asList(new String[] { "Python", "C++", "Java", "PHP" });
 
		List<String> sortedListOfLanguages = listOfLanguages.stream()
				                                              .sorted()
				                                              .collect(Collectors.toList());
		System.out.println(sortedListOfLanguages);
 
		List<String> sortedListOfLanguagesRev = listOfLanguages.stream()
				                                                 .sorted(Comparator.reverseOrder())
				                                                 .collect(Collectors.toList());
		System.out.println(sortedListOfLanguagesRev);  
	}
 
}

输出:

[C++, Java, PHP, Python]
[Python, PHP, Java, C++]

排序自定义对象列表

按自然秩序对学生列表进行排序

创建一个名为的类 Student.java

package org.igi.theitroad;
 
public class Student{
	
	String name;
	int age;
	
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}

让我们使用Stream的Salted()来对学生的列表进行排序。

package org.igi.theitroad;
 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
 
public class SortListOfStudents {
 
	public static void main(String[] args) {
		List<Student> studentsList = getListOfStudents();
		
		List<Student> sortedStudentsList= studentsList.stream()
				                                          .sorted()
				                                          .collect(Collectors.toList());
		System.out.println(sortedStudentsList);
	}
 
	public static List<Student> getListOfStudents()
	{
		List<Student> studentList=new ArrayList<>();
		
		Student s1=new Student("Peter",21);
		Student s2=new Student("Harshal",18);
		Student s3=new Student("Andy",17);
		Student s4=new Student("Mary",20);
		Student s5=new Student("Peter",19);
		
		studentList.add(s1);
		studentList.add(s2);
		studentList.add(s3);
		studentList.add(s4);
		studentList.add(s5);
		
		return studentList;
	}
}

运行后报错:

Exception in thread “main" java.lang.ClassCastException: org.arpit.theitroad.Student cannot be cast to java.lang.Comparable at java.util.Comparators$NaturalOrderComparator.compare(Comparators.java:47) at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) at java.util.TimSort.sort(TimSort.java:220) at java.util.Arrays.sort(Arrays.java:1512) at java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:353) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:483) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566) at org.arpit.theitroad.SortListOfStudents.main(SortListOfStudents.java:14)

你知道为什么我们在这里得到异常吗?
我们得到了 ClassCastException例外,因为我们没有实施 Comparable接口 Student类。

让我们实现类似的接口

Student类。

package org.igi.theitroad;
 
public class Student implements Comparable<Student>{
	
	String name;
	int age;
	
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	
	@Override
	public int compareTo(Student o) {
		return this.getName().compareTo(o.getName());
	}
 
}

学生列表将按学生名称排序。

按逆自然顺序排序学生列表

按下降订单按名称排序学生列表。

package org.igi.theitroad;
 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
 
public class SortListOfStudents {
 
	public static void main(String[] args) {
		List<Student> studentsList = getListOfStudents();
		
		List<Student> sortedListOfStudent2 = listOfStudents.stream()
		                                                   .sorted(Comparator.reverseOrder())
		                                                   .collect(Collectors.toList());
		System.out.println(sortedStudentsList);
	}
 
	public static List<Student> getListOfStudents()
	{
		List<Student> studentList=new ArrayList<>();
		
		Student s1=new Student("Peter",21);
		Student s2=new Student("Harshal",18);
		Student s3=new Student("Andy",17);
		Student s4=new Student("Mary",20);
		Student s5=new Student("Peter",19);
		
		studentList.add(s1);
		studentList.add(s2);
		studentList.add(s3);
		studentList.add(s4);
		studentList.add(s5);
		
		return studentList;
	}
}

使用比较器按年龄排序学生列表

package org.igi.theitroad;
 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
 
public class SortListOfStudents {
 
	public static void main(String[] args) {
		List<Student> studentsList = getListOfStudents();
		
		List<Student> studentsListByAge = studentsList.stream()
                                                         .sorted((s1,s2) -> s1.getAge()-s2.getAge())
                                                         .collect(Collectors.toList());
		System.out.println(studentsListByAge);
	}
 
	public static List<Student> getListOfStudents()
	{
		List<Student> studentList=new ArrayList<>();
		
		Student s1=new Student("Peter",21);
		Student s2=new Student("Harshal",18);
		Student s3=new Student("Andy",17);
		Student s4=new Student("Mary",20);
		Student s5=new Student("Peter",19);
		
		studentList.add(s1);
		studentList.add(s2);
		studentList.add(s3);
		studentList.add(s4);
		studentList.add(s5);
		
		return studentList;
	}
}

你也可以使用 Comparator.comparing(Function&lt;? super T, ? extends U> keyExtractor)根据年龄为基础进行排序。 Comparator.comparing()接受从类型映射排序键的函数,并返回由该排序键进行比较的比较器。

让我们说你想在年龄的基础上排序学生列表。
我们可以从学生对象中提取排序键年龄 Comparator.comparing()将返回一个比较器,它将排序该排序键。

Function<Student,Integer> fun = (s) -> s.getAge();
	List<Student> studentsListByAge = studentsList.stream()
                                               .sorted(Comparator.comparing(fun))
                                               .collect(Collectors.toList());

这里 Comparator.comparing()返回基于年龄的新比较器进行排序。

我们还可以在此处使用方法引用,因为我们只是在调用s。

GetAge()在函数接口中。

Function<Student,Integer> fun = Student::getAge
	List<Student> studentsListByAge = studentsList.stream()
                                          	.sorted(Comparator.comparing(fun))
                                                .collect(Collectors.toList());

假设我们想根据年龄按降序排序学生列表。
我们可以传递另一个比较器 Comparator.comparing()基于排序键进行自定义排序。

List<Student> sortedListOfStudent5 = listOfStudents.stream()
		                                                   .sorted(Comparator.comparing(Student::getAge,(age1,age2) -> age2 - age1))
		                                                   .collect(Collectors.toList());

其中比较器.paring()有两个参数。 Student::getAge定义排序键。 (age1,age2) -> age2 - age1)根据排序密钥定义自定义排序。

这是完整的例子。

package org.igi.theitroad;
 
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
 
public class SortListOfStudents {
 
	public static void main(String[] args) {
		List<Student> sList = getListOfStudents();
		
		Function<Student,Integer> fun = (s) -> s.getAge();
		List<Student> sListByAge = sList.stream()
                                         .sorted(Comparator.comparing(fun))
                                         .collect(Collectors.toList());
		System.out.println("Sorted list by age ascending: "+sListByAge);
		
		List<Student> sListByAgeRev = sList.stream()
                                           .sorted(Comparator.comparing(Student::getAge
                                                        		         ,(age1,age2) -> age2 - age1))
                                           .collect(Collectors.toList());
		
		System.out.println("Sorted list by age descending: "+sListByAgeRev);
	}
 
	public static List<Student> getListOfStudents()
	{
		List<Student> studentList=new ArrayList<>();
		
		Student s1=new Student("Peter",21);
		Student s2=new Student("Harshal",18);
		Student s3=new Student("Andy",17);
		Student s4=new Student("Mary",20);
		Student s5=new Student("Peter",19);
		
		studentList.add(s1);
		studentList.add(s2);
		studentList.add(s3);
		studentList.add(s4);
		studentList.add(s5);
		
		return studentList;
	}
}

按名称和年龄排序学生列表

假设我们想按名称列出学生,如果姓名是相同的,那么我们需要按年龄排序。

我们可以使用Comparator.ThenComparing()使用Comparator.comparing()来实现相同的。

让我们在举例的帮助下看看。

package org.igi.theitroad;
 
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
 
public class SortListOfStudents {
 
	public static void main(String[] args) {
		List<Student> sList = getListOfStudents();
		
		List<Student> sListByNameAge = sList.stream()
                                           .sorted(Comparator.comparing(Student::getName)
                                        		             .thenComparing(Student::getAge))
                                           .collect(Collectors.toList());
		
		System.out.println(sListByNameAge);
	}
 
	public static List<Student> getListOfStudents()
	{
		List<Student> studentList=new ArrayList<>();
		
		Student s1=new Student("Peter",21);
		Student s2=new Student("Harshal",18);
		Student s3=new Student("Andy",17);
		Student s4=new Student("Mary",20);
		Student s5=new Student("Peter",19);
		
		studentList.add(s1);
		studentList.add(s2);
		studentList.add(s3);
		studentList.add(s4);
		studentList.add(s5);
		
		return studentList;
	}
}

正如你所看到的,有两个学生命名 Peter在列表中,按年龄排序。