Domain
As I have stated in my comment, I would recommend using a Person-POJO to bind firstName and lastName in a semantic way:
class Person {
public static final String PERSON_TO_STRING_FORMAT = "{f: %s, l: %s}";
private final String firstName;
private final String lastName;
private Person(final String firstName, final String lastName) {
this.firstName = Objects.requireNonNull(firstName);
this.lastName = Objects.requireNonNull(lastName);
}
public static Person of(final String firstName, final String lastName) {
return new Person(firstName, lastName);
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
@Override
public String toString() {
return String.format(PERSON_TO_STRING_FORMAT, getFirstName(), getLastName());
}
}
To convert two String[]s firstNames and lastNames into a List<Person>, one can provide a method:
public static List<Person> constructPersons(
final String[] firstNames,
final String[] lastNames) {
if (firstNames.length != lastNames.length) {
throw new IllegalArgumentException("firstNames and lastNames must have same length");
}
return IntStream.range(0, firstNames.length)
.mapToObj(index -> Person.of(firstNames[index], lastNames[index]))
.collect(Collectors.toCollection(ArrayList::new));
}
A remark on this method: Here, we use collect(Collectors.toCollection(...)) instead of collect(Collectors.toList()) to have some control with respect to list mutability since we are going to sort the list.
From here on there are two general routes: Either one makes Person comparable by public class Person implements Comparable<Person> or one writes a Comparator<Person>. We will discuss both possibilities.
Challenge
The goal is to sort Person-objects. The primary criteria for sorting is the first name of the person. If two persons have equal first names, then they should be ordered by their last names. Both first- and last name are String-objects and should be ordered in lexicographical order, which is String's natural order.
Solution 1: Implementing Comparable<Person> on Person
The logic to implement the comparison is straight-forward:
- Compare the
firstNames of two persons using equals(...).
- If they are equal, compare the
lastNames using compareTo(...) and return the result.
- Otherwise, compare the
firstNames with compareTo(...) and return the result.
The corresponding method would then look like this:
public class Person implements Comparable<Person> {
...
@Override
public final int compareTo(final Person that) {
if (Objects.equals(getFirstName(), that.getFirstName())) {
return getLastName().compareTo(that.getLastName());
}
return getFirstName().compareTo(that.getFirstName());
}
...
}
While not strictly necessary, it is recommended that the natural ordering of a class (i.e. the Comparable-implementation) is consistent with its equals(...)-implementation. Since this is not the case right now, I would recommend overriding equals(...) and hashCode():
public class Person implements Comparable<Person> {
...
@Override
public final boolean equals(Object thatObject) {
if (this == thatObject) {
return true;
}
if (thatObject == null || getClass() != thatObject.getClass()) {
return false;
}
final Person that = (Person) thatObject;
return Objects.equals(getFirstName(), that.getFirstName()) &&
Objects.equals(getLastName(), that.getLastName());
}
@Override
public final int hashCode() {
return Objects.hash(getFirstName(), getLastName());
}
...
}
The following code demonstrates how to create and order a List<Person> from two String[]:
final List<Person> persons = constructPersons(
new String[]{"Clair", "Alice", "Bob", "Alice"},
new String[]{"Clear", "Wonder", "Builder", "Ace"}
);
Collections.sort(persons);
System.out.println(persons);
Solution 2: Implementing a Comparator<Person>
A traditional implementation of a comparator realizing the sort comparison given in the challenge-section may look like this:
class PersonByFirstNameThenByLastNameComparator implements Comparator<Person> {
public static final PersonByFirstNameThenByLastNameComparator INSTANCE =
new PersonByFirstNameThenByLastNameComparator();
private PersonByFirstNameThenByLastNameComparator() {}
@Override
public int compare(final Person lhs, final Person rhs) {
if (Objects.equals(lhs.getFirstName(), rhs.getFirstName())) {
return lhs.getLastName().compareTo(rhs.getLastName());
}
return lhs.getFirstName().compareTo(rhs.getFirstName());
}
}
A example call may look like this:
final List<Person> persons = constructPersons(
new String[]{"Clair", "Alice", "Bob", "Alice"},
new String[]{"Clear", "Wonder", "Builder", "Ace"}
);
persons.sort(PersonByFirstNameThenByLastNameComparator.INSTANCE);
System.out.println(persons);
With Java 8, the construction of a Comparator has been simplified through the Comparator.comparing-API. To define a Comparator realizing the order given in section Challenge with the Comparator.comparing-API, we only need one line of code:
Comparator.comparing(Person::getFirstName)
.thenComparing(Person::getLastName)
The following code demonstrates how this Comparator is used to sort a List<Person>:
final List<Person> persons = constructPersons(
new String[]{"Clair", "Alice", "Bob", "Alice"},
new String[]{"Clear", "Wonder", "Builder", "Ace"}
);
persons.sort(Comparator.comparing(Person::getFirstName)
.thenComparing(Person::getLastName));
System.out.println(persons);
Closing Notes
A MRE is available on Ideone.
I would question the initial design decision to split up first- and last names into two separate arrays. I opted to not include the method List<Person> constructPersons(String[] firstNames, String[] lastNames) in class Person since this is just adapter-code. It should be contained in some mapper, but is not a functionality that is existential for Person.
Person-class, constructPerson-instances fromfirstNameandlastNameand then sort aList<Person>by either implementingComparable<Person>onPersonor writing a separateComparator<Person>.Stringin this case seems to be a quite poor choice. You should create a class that would represent the Person as @Turing85 has mentioned. It would be extremely hard to maintain order if the list is not static.