In my program an array fClasses
of fixed length [7] of objects is created, each object is a class FClass
that contains 3 Strings
, an int
, and an int[]
. These values are read from a .txt file and added to a specific index of the array based on the value of the int
. There are less entries in the .txt file then there are indices in the array so the array ends up looking something like this:
fClasses[0] { str1, str2, str3, int1, int [] {1,2,3,4,5}}
fClasses[1] { str1, str2, str3, int1, int [] {1,2,3,4,5}}
fClasses[2] { str1, str2, str3, int1, int [] {1,2,3,4,5}}
fClasses[3] null
fClasses[4] null
fClasses[5] { str1, str2, str3, int1, int [] {1,2,3,4,5}}
fClasses[6] { str1, str2, str3, int1, int [] {1,2,3,4,5}}
Later in the program I need to sort the array based on the average of the ints
in the int[]
. I have a working method to return this but when I try to sort the array using compareTo
and Arrays.sort
I get a long list of errors starting with these:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at java.util.ComparableTimSort.countRunAndMakeAscending(Unknown Source)
at java.util.ComparableTimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at FProg.sortClasses(FProg.java:228)
My compareTo
method looks like this and it's located in a class that implements Comparable
:
public int compareTo(FClass other)
{
if (other == null || this.avg == other.avg)
{
return 0;
}
else if (this.avg < other.avg)
{
return -1;
}
else
{
return 1;
}
}
And I'm trying to call this method to do the sorting:
public void sortClasses()
{
Arrays.sort(fClasses, 0, MAX_CLASSES);
}
I have tested it with a .txt file that contains enough entries to fill the array and the sort works correctly in that case, so I believe the problem I'm having is that my sort method can't sort an array with null elements in it. Is there any way this can be achieved?
You need your own Comparator
implementation and check for nulls and return 0
Arrays.sort(fClasses, new Comparator<FClass>() {
@Override
public int compare(FClass o1, FClass o2) {
if (o1 == null && o2 == null) {
return 0;
}
if (o1 == null) {
return 1;
}
if (o2 == null) {
return -1;
}
return o1.compareTo(o2);
}});
Using Java 8, you can easily build the comparator you need:
Arrays.sort(fClasses, Comparator.nullsFirst(Comparator.naturalOrder()));
Use nullsLast
instead if that's what you want, of course.
You have to create a Comparator<FClass>
, rather than use a Comparable<FClass>
.
public class FClassComparator implements Comparator<FClass>
{
public int compare(FClass left, FClass right) {
// Swap -1 and 1 here if you want nulls to move to the front.
if (left == null) return right == null ? 0 : 1;
if (right == null) return -1;
// you are now guaranteed that neither left nor right are null.
// I'm assuming avg is int. There is also Double.compare if they aren't.
return Integer.compare(left.avg, right.avg);
}
}
Then call sort via:
Arrays.sort(fClassArray, new FClassComparator());
With Apache Commons Collections 4 you can use ComparatorUtils to do that:
Collections.sort(arr, ComparatorUtils.nullLowComparator(ComparatorUtils.NATURAL_COMPARATOR));
By importing the org.apache.commons.collections.comparators package of the
Apache 2.1.1 Release library, I'm able to sort a list, such as an ArrayList<String>
, using the NullComparator
as the second argument of the Collections.sort()
method, as follows:
ArrayList<String> list = new ArrayList<String>();
list.add("foo");
list.add("bar");
list.add("baz");
list.add(null);
// Sort the list
Collections.sort(list, new NullComparator(true));
System.out.println(list);
// outputs:
// [bar, baz, foo, null]
The thing I like about this approach is that the NullComparator
has an overload constructor which allows you to specify whether you want null
to be considered a high value or a low value, which seems pretty intuitive to me.
NullComparator(boolean nullsAreHigh)
Hope this helps someone!
来源:https://stackoverflow.com/questions/27556104/how-to-sort-an-array-of-objects-containing-null-elements