Grouping by fields of inner object - java

I have following two classes:
class Man {
private int id;
private String firstName;
private String lastName;
private int age;
private int countOfChildren;
private Address address;
}
class Address {
private Country country;
private City city;
private String street;
private long quantityOfPeople;
}
I have no idea how to group List<Man> by street and city fields of Address class. How can I do it?

Collectors class provides Collectors.groupingBy(keyProvider, downstream) you can use to group by a pair of values. To pair two values you can either use AbstractMap.SimpleEntry or you can implement your own Pair<T,K> class that represents a pair of two values (it's worth mentioning that you will have to implement hashCode() and equals(object) methods in your Pair class if you want to use it as a key in a hash map). Also two values you want to pair in a key have to implement hashCode() and equals(object) methods - it's worth using immutable classes in this case.
The whole grouping part can be done by:
final Map<Map.Entry<City, String>, List<Man>> groupedByCityAndStreet = people.stream()
.collect(Collectors.groupingBy(
man -> new AbstractMap.SimpleEntry<>(man.getAddress().getCity(), man.getAddress().getStreet()),
Collectors.toList()
));
In this example I have used AbstractMap.SimpleEntry to represent a pair of Country and street. It creates a map where for each key it groups a list of Man object based of country and street. Below you can find a full example:
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
public class GroupByTest {
public static void main(String[] args) {
final List<Man> people = Arrays.asList(
new Man(1, "John", "Doe", 20, 0, new Address(new Country("England"), new City("London"), "Test Street 2", 10000)),
new Man(2, "Mary", "Smith", 54, 4, new Address(new Country("Germany"), new City("Berlin"), "Maine Strasse 32", 10000)),
new Man(3, "James", "Rose", 13, 0, new Address(new Country("England"), new City("London"), "Test Street 2", 10000)),
new Man(4, "Vincent", "Dog", 43, 2, new Address(new Country("Germany"), new City("Berlin"), "Volkswagen Platz 31", 10000)),
new Man(5, "Arnold", "Smoke", 72, 3, new Address(new Country("Italy"), new City("Rome"), "Pepperoni 31", 10000)),
new Man(6, "Katy", "Puppet", 33, 3, new Address(new Country("England"), new City("London"), "Test Street 3", 10000))
);
final Map<Map.Entry<City, String>, List<Man>> groupedByCityAndStreet = people.stream()
.collect(Collectors.groupingBy(
man -> new AbstractMap.SimpleEntry<>(man.getAddress().getCity(), man.getAddress().getStreet()),
Collectors.toList()
));
// Print people associated with given city and street to console
groupedByCityAndStreet.forEach((k, v) -> {
System.out.println("People associated with " + k.getKey().name + ", " + k.getValue() + ":");
v.forEach(man -> {
System.out.println(man);
});
});
}
static final class Man {
private final int id;
private final String firstName;
private final String lastName;
private final int age;
private final int countOfChildren;
private final Address address;
public Man(int id, String firstName, String lastName, int age, int countOfChildren, Address address) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.countOfChildren = countOfChildren;
this.address = address;
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public int getCountOfChildren() {
return countOfChildren;
}
public Address getAddress() {
return address;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Man man = (Man) o;
return id == man.id &&
age == man.age &&
countOfChildren == man.countOfChildren &&
Objects.equals(firstName, man.firstName) &&
Objects.equals(lastName, man.lastName) &&
Objects.equals(address, man.address);
}
#Override
public int hashCode() {
return Objects.hash(id, firstName, lastName, age, countOfChildren, address);
}
#Override
public String toString() {
return "Man{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", age=" + age +
", countOfChildren=" + countOfChildren +
", address=" + address +
'}';
}
}
static class Address {
private final Country country;
private final City city;
private final String street;
private final long quantityOfPeople;
public Address(Country country, City city, String street, long quantityOfPeople) {
this.country = country;
this.city = city;
this.street = street;
this.quantityOfPeople = quantityOfPeople;
}
public Country getCountry() {
return country;
}
public City getCity() {
return city;
}
public String getStreet() {
return street;
}
public long getQuantityOfPeople() {
return quantityOfPeople;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return quantityOfPeople == address.quantityOfPeople &&
Objects.equals(country, address.country) &&
Objects.equals(city, address.city) &&
Objects.equals(street, address.street);
}
#Override
public int hashCode() {
return Objects.hash(country, city, street, quantityOfPeople);
}
#Override
public String toString() {
return "Address{" +
"country=" + country +
", city=" + city +
", street='" + street + '\'' +
", quantityOfPeople=" + quantityOfPeople +
'}';
}
}
static class City {
private final String name;
public City(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
City city = (City) o;
return Objects.equals(name, city.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "City{" +
"name='" + name + '\'' +
'}';
}
}
static class Country {
private final String name;
public Country(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Country country = (Country) o;
return Objects.equals(name, country.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "Country{" +
"name='" + name + '\'' +
'}';
}
}
}
When you run this example you will something like this in the console:
People associated with Rome, Pepperoni 31:
Man{id=5, firstName='Arnold', lastName='Smoke', age=72, countOfChildren=3, address=Address{country=Country{name='Italy'}, city=City{name='Rome'}, street='Pepperoni 31', quantityOfPeople=10000}}
People associated with London, Test Street 3:
Man{id=6, firstName='Katy', lastName='Puppet', age=33, countOfChildren=3, address=Address{country=Country{name='England'}, city=City{name='London'}, street='Test Street 3', quantityOfPeople=10000}}
People associated with Berlin, Volkswagen Platz 31:
Man{id=4, firstName='Vincent', lastName='Dog', age=43, countOfChildren=2, address=Address{country=Country{name='Germany'}, city=City{name='Berlin'}, street='Volkswagen Platz 31', quantityOfPeople=10000}}
People associated with Berlin, Maine Strasse 32:
Man{id=2, firstName='Mary', lastName='Smith', age=54, countOfChildren=4, address=Address{country=Country{name='Germany'}, city=City{name='Berlin'}, street='Maine Strasse 32', quantityOfPeople=10000}}
People associated with London, Test Street 2:
Man{id=1, firstName='John', lastName='Doe', age=20, countOfChildren=0, address=Address{country=Country{name='England'}, city=City{name='London'}, street='Test Street 2', quantityOfPeople=10000}}
Man{id=3, firstName='James', lastName='Rose', age=13, countOfChildren=0, address=Address{country=Country{name='England'}, city=City{name='London'}, street='Test Street 2', quantityOfPeople=10000}}
Hope it helps.

Related

How to find getter method on basis of JSON Value using Jackson

I have json similar to this :
Groups":[
{
"LogicalOperator":"AND",
"condition":[
{
"column":"name",
"Operator":"CONTAINS",
"Value":"Shiva"
},
{
"column":"address",
"Operator":"NOT CONTAINS",
"Value":"Vijay Nagar"
},
{
"column":"city",
"Operator":"EQUAL",
"Value":"Bengaluru"
},
{
"column":"country",
"Operator":"NOT EQUAL",
"Value":"India"
}
]
}
How to find getter method based on column value.
Example: Below column is having "name", "address", "city" and "country".
If the column value is "name" then dynamically I want find getName() method, if the column value is "address" then it should be getAddress()...
Below is the pojo:
public class CustomerPojo {
private String name;
private int age;
private String address;
private String city;
private String country;
public CustomerPojo(String name, String address, String city, String country,int age) {
super();
this.name = name;
this.age=age;
this.address = address;
this.city = city;
this.country = country;
}
#Override
public int hashCode() {
return Objects.hash(address, age, city, country, name);
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CustomerPojo other = (CustomerPojo) obj;
return Objects.equals(address, other.address) && age == other.age && Objects.equals(city, other.city)
&& Objects.equals(country, other.country) && Objects.equals(name, other.name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#Override
public String toString() {
return "CustomerPojo [name=" + name + ", age=" + age + ", address=" + address + ", city=" + city + ", country="
+ country + "]";
}
}
Below is the code which I have tried. But I want to do it dynamically.
private List<CustomerPojo> groupOperatorAND(JsonNode condNode, List<CustomerPojo> list) {
// String jsonNode = condNode
// System.out.println(jsonNode);
String column = condNode.findValue("column").asText();
String operator = condNode.findValue("Operator").asText();
String value = condNode.findValue("Value").asText();
switch (operator) {
case "CONTAINS":
if (column.equals("name")) {
containsList = list.stream().filter(li -> li.getName().contains(value)).collect(Collectors.toList());
} else {
containsList = list.stream().filter(li -> li.getAddress().contains(value)).collect(Collectors.toList());
}
// System.out.println(containsList);
// objList.add(containsList);
break;
case "NOT CONTAINS":
if (column.equals("name")) {
notContainsList = containsList.stream().filter(li -> !li.getName().contains(value))
.collect(Collectors.toList());
} else {
notContainsList = containsList.stream().filter(li -> !li.getAddress().contains(value))
.collect(Collectors.toList());
}
// System.out.println(notContainsList);
// objList.add(notContainsList);
break;
case "EQUAL":
if (column.equals("name")) {
equalList = notContainsList.stream().filter(li -> li.getName().equals(value))
.collect(Collectors.toList());
} else {
equalList = notContainsList.stream().filter(li -> li.getAddress().equals(value))
.collect(Collectors.toList());
}
// System.out.println(equalList);
// objList.add(equalList);
break;
case "NOT EQUAL":
if (column.equals("name")) {
notEqualList = equalList.stream().filter(li -> !li.getName().equals(value))
.collect(Collectors.toList());
} else {
notEqualList = equalList.stream().filter(li -> !li.getAddress().equals(value))
.collect(Collectors.toList());
}
//System.out.println("AND Group Result --> " + notEqualList);
// objList.add(notEqualList);
break;
default:
System.out.println("No Operator matches");
}
return notEqualList;
}
If you put this code into a static method or in a constructor so it is only executed once, it will build a map where the key is the "column" name and the value is the associated get method from your CustomerPojo class.
final Map<String, Method> getters = Arrays.asList(CustomerPojo.class.getMethods()).stream()
.filter(mth -> mth.getName().startsWith("get")).filter(mth -> !mth.getName().equals("getClass"))
.collect(Collectors.toMap(
mth -> mth.getName().substring(3, 4).toLowerCase() + mth.getName().substring(4), mth -> mth));
The code streams the array of methods from your CustomerPojo class and filters out all but the "getter" methods.
It then collects the remaining methods into a map where the key is the name of the getter after stripping off "get" and lowercasing the first character.
With this you should be able to:
Method mth = getters.get(columnName);

how to add two objects?

I have two classes:-
public class Employee {
private String name;
private String DOB;
private String techicalSkill;
Employee(){
}
Employee(String name, String DOB, String techicalSkill){
this.name=name;
this.DOB=DOB;
this.techicalSkill=techicalSkill;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDOB() {
return DOB;
}
public void setDOB(String dOB) {
DOB = dOB;
}
public String getTechicalSkill() {
return techicalSkill;
}
public void setTechicalSkill(String techicalSkill) {
this.techicalSkill = techicalSkill;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((DOB == null) ? 0 : DOB.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((techicalSkill == null) ? 0 : techicalSkill.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (DOB == null) {
if (other.DOB != null)
return false;
} else if (!DOB.equals(other.DOB))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (techicalSkill == null) {
if (other.techicalSkill != null)
return false;
} else if (!techicalSkill.equals(other.techicalSkill))
return false;
return true;
}
#Override
public String toString() {
return "Employee [name=" + name + ", DOB=" + DOB + ", techicalSkill=" + techicalSkill + "]";
}
}
and
package learning;
public class Person {
private String address;
private int age;
private int weight;
Person(){
}
public Person(String address, int age, int weight) {
super();
this.address = address;
this.age = age;
this.weight = weight;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + age;
result = prime * result + weight;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (address == null) {
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (age != other.age)
return false;
if (weight != other.weight)
return false;
return true;
}
#Override
public String toString() {
return "Person [address=" + address + ", age=" + age + ", weight=" + weight + "]";
}
}
Now i have created a main class inside which the details are present:-
import java.util.ArrayList;
public class Main {
Employee e1 = new Employee();
Person p1 = new Person();
public static void main(String[] args) {
ArrayList<Employee> arraylist = new ArrayList<>();
arraylist.add(new Employee("Somduti", "31-08-1992", "Java"));
arraylist.add(new Employee("abc", "30-01-1995", "Android"));
arraylist.add(new Employee("xyz", "24-12-1988", "DotNet"));
arraylist.add(new Employee("Sanj", "01-10-1986", "IOS"));
arraylist.add(new Employee("Pink", "19-07-1991", "ETL"));
System.out.println(arraylist);
ArrayList<Person> arraylist1 = new ArrayList<>();
arraylist1.add(new Person("India", 27, 57));
arraylist1.add(new Person("US", 22, 64));
arraylist1.add(new Person("Australia", 31, 69));
arraylist1.add(new Person("France", 33, 77));
arraylist1.add(new Person("Germany", 28, 55));
System.out.println(arraylist1);
}
}
I want to add the two Objects and print the result as below:-
name=Somduti, DOB=31-08-1992, techicalSkill=Java address=India, age=27, weight=57
How do I that?
I think what you want to achieve is a relation between employees and persons. There are various ways to do that. Here are two common solutions:
Association: Add a person-field to the employee class. This looks like: "private Person person;" within the employee class.
Inheritance: An employee is a specific type of person, so you can let employee "extend" the person class. This looks like: public class Employee extends Person ...
Both ways have advantages and disadvantages. For example: Inheritance is a strong relationship, that you might want in this case. Association is a weaker type of relation, so that you could "replace" the person information of an employee (which might not be want you want).
Add the below additional field in the Employee class as follows:
public class Employee {
private String name;
private String DOB;
private String techicalSkill;
private Person person; // Additional field
Employee() {
}
/**
* #param name
* #param dOB
* #param techicalSkill
* #param person
*/
public Employee(final String name, final String dOB, final String techicalSkill, final Person person) {
super();
this.name = name;
this.DOB = dOB;
this.techicalSkill = techicalSkill;
this.person = person; //additional argument in Constructor
}
}
P.S: No changes to the Person class
Test Main:
Person person = new Person("India", 27, 57);
Employee employee = new Employee("Somduti", "31-08-1992", "Java", person);
System.out.println("name= " + employee.getName() + ", DOB= " + employee.getDOB() + ",techicalSkill= " +
employee.getTechicalSkill() + " address= " + employee.getPerson().getAddress() + ", age= " +
employee.getPerson().getAge() + " weight= " + employee.getPerson().getWeight());
Output:
name= Somduti, DOB= 31-08-1992,techicalSkill= Java address= India, age= 27 weight= 57

Get duplicated items with specific format from Java Stream

I'm new with Java streams and I'm playing around with them right now. Given that I receive a list of persons I want to detect which of them are duplicated and print them as "{Id1} is duplicated with {Id3}{Id4} and its duplicated values are Name, Lastname, FamilyName and Birthday"
So this is my person class, I have already override the equals method in order to get the duplicated based on my criterias
public class Person {
private int id;
private String name;
private String familyName;
private String birthday;
private String city;
public Person(int id, String name, String familyName, String birthday, String city) {
this.id = id;
this.name = name;
this.familyName = familyName;
this.birthday = birthday;
this.city = city;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFamilyName() {
return familyName;
}
public void setFamilyName(String familyName) {
this.familyName = familyName;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
#Override
public int hashCode() {
return Objects.hash( name,familyName,birthday,city);
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return false;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
if (!Objects.equals(name, other.name)) {
return false;
}
if (!Objects.equals(familyName, other.familyName)) {
return false;
}
if (!Objects.equals(birthday, other.birthday)) {
return false;
}
return true;
}
}
Then, I'm getting the list of duplicates in the following method
personList.stream()
.filter(p -> personList.contains(p))
.collect(Collectors.toList()).forEach(p-> {
System.out.println(p.getId() + " " + p.getName() + " " + p.getFamilyName() + " " + p.getBirthday());
});
It prints the following:
2 Andres Gonzalez 12/4/1990
4 Maureen Perez 15/07/92
7 Andres Gonzalez 12/4/1990
9 Maureen Perez 15/07/92
11 Maureen Perez 15/07/92
As you can see ID's 2 and 7 are duplicated and also 4,9 and 11 are duplicated and those ones are the ones that I need to print in that format but I don't know how to do it with streams so far.
First of all, you should fix your hashCode() implementation to match your equals. If two objects are equal, they must have the same hashCode().
Now, your Stream pipeline returns all elements, since your filter's Predicate will always return true.
Instead, you can group equal elements of the List:
Map<Person,List<Integer>> grouped =
personList.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.mapping(Person::getId,
Collectors.toList())));
Now, for each Person, you have an associated List of identifiers.
You can iterate this Map and print the Persons having Lists with size > 1.
For example:
personList.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.mapping(Person::getId,
Collectors.toList())));
.entrySet()
.stream()
.filter(e -> e.getValue().size() > 1)
.forEach(e -> System.out.println(e.getKey().getId() + " " + e.getKey().getName() + " " + e.getKey().getFamilyName() + " " + e.getKey().getBirthday() + " " + e.getValue()));

How to sort data in repository into alphabetical order using .stream()

I am trying to create a method that sorts and outputs data I have stored in a repository into alphabetical order using .stream(). Currently I have a method that sorts the data by CityID in numeric order which I will add below. Is there a way to adapt it to sort the same data but by CityName in Alphabetical order?
CityID Method -
private void listCityDataInCityIdOrder() {
System.out.format("\033[31m%s\033[0m%n", "City Id Order");
System.out.format("\033[31m%s\033[0m%n", "=============");
repository.getItems()
.stream()
.sorted()
.map(c -> c.toString())
.forEach(str -> System.out.print(str));
}
Data Set -
1,"Cartagena","Spain",3
"2015",0.2,33,26,6,"S"
"2016",0.0,33,24,8,"SSW"
"2017",0.0,32,25,6,"E"
2,"Glasgow","Scotland",3
"2015",0.0,19,8,3,"SE"
"2016",0.1,21,11,6,"SE"
"2017",2.1,19,11,9,"SW"
City Model Class -
package model;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
/**
*
* #author mga
*/
public class City implements Comparable<City>{
private final int id;
private String cityName;
private String country;
private List<YearData> yearDataCollection;
private static int lastIdAllocated = 0;
static final char EOLN='\n';
static final String QUOTE="\"";
public City() {
this.id = ++lastIdAllocated;
this.cityName = "TBC";
this.country = "TBC";
this.yearDataCollection = new ArrayList<>();
}
public City(String cityName, String country) {
this.id = ++lastIdAllocated;
this.cityName = cityName;
this.country = country;
this.yearDataCollection = new ArrayList<>();
}
public City(String cityName, String country, List<YearData> yearDataCollection) {
this.id = ++lastIdAllocated;
this.cityName = cityName;
this.country = country;
this.yearDataCollection = yearDataCollection;
}
public City(int id, String cityName, String country, List<YearData> yearDataCollection) {
this.id = id;
this.cityName = cityName;
this.country = country;
this.yearDataCollection = yearDataCollection;
if (id > City.lastIdAllocated)
City.lastIdAllocated = id;
}
/**
* #return the id
*/
public int getId() {
return id;
}
// Methods required:
public String getCityName() {
return this.cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public String getCountry() {
return this.country;
}
public void setCountry(String country) {
this.country = country;
}
public List<YearData> getYearDataCollection() {
return this.yearDataCollection;
}
public void setYearDataCollection(List<YearData> yearDataCollection) {
this.yearDataCollection = yearDataCollection;
}
public void addYearData(YearData yearData) {
this.yearDataCollection.add(yearData);
}
#Override
public String toString() {
return "\nCity Id: " + id + " - City Name: " + cityName +
" - Country: " + country + "\nData: " + yearDataCollection + "\n";
}
public String toString(char delimiter) {
final char EOLN='\n';
final String QUOTE="\"";
String str = Integer.toString(this.id) + delimiter +
QUOTE + this.cityName + QUOTE + delimiter +
QUOTE + this.country + QUOTE + delimiter +
Integer.toString(yearDataCollection.size()) + EOLN;
for (YearData yearData : yearDataCollection) {
str += yearData.toString();
}
return str;
}
public boolean equals(Object object) {
if (this == object) return true;
if (!(object instanceof City)) return false;
if (!super.equals(object)) return false;
City city = (City) object;
return getId() == city.getId() &&
java.util.Objects.equals(getCityName(), city.getCityName()) &&
java.util.Objects.equals(getCountry(), city.getCountry()) &&
java.util.Objects.equals(getYearDataCollection(), city.getYearDataCollection());
}
public int hashCode() {
return Objects.hash(super.hashCode(), getId(), getCityName(), getCountry(), getYearDataCollection());
}
#Override
public int compareTo(City compareCity) {
int cityId =
((City) compareCity).getId();
//ascending order
return this.id - cityId;
//descending order
//return cityId - this.id;
}
public static Comparator<City> CityComparator = new Comparator<City>() {
#Override
public int compare(City city1, City city2) {
String cityName1 = city1.getCityName();
String cityName2 = city2.getCityName();
//ascending order
//return cityName1.compareTo(cityName2);
//descending order
return cityName2.compareTo(cityName1);
}
};
}
sure, change your sorted to:
.sorted(Comparator.comparing(City::getCityName))
or using lambda:
.sorted(Comparator.comparing(c -> c.getCityName()))
You can simplify your Comparator
public static Comparator<City> CityComparator = new Comparator<City>() {
#Override
public int compare(City city1, City city2) {
String cityName1 = city1.getCityName();
String cityName2 = city2.getCityName();
//ascending order
//return cityName1.compareTo(cityName2);
//descending order
return cityName2.compareTo(cityName1);
}
};
to just this :
Comparator<City> cityComparatorSimplified = Comparator
.comparing(City::getCityName).reversed(); // reverse for descending order
and then use it further while sorting as
repository.getItems().stream()
.sorted(cityComparatorSimplified)
.map(Object::toString)
.forEach(System.out::print);

java toString() is returning null from class [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
This is Java, using BlueJ.
I have four classes called Person, Letter, Address and PhoneNumber. In each, I override the toString() method to return a concatenated string of the values I want from the class. When calling the Letter toString(), it is returning null on all values.
The idea is to use the hard coded information, pass it into the appropriate class, and return it in a standard letter format.
Am I headed in the right direction for printing out the information hard coded, or should I go a different route? This is a homework problem, but I feel I have hit a brick wall.
Here are the classes:
public class Person
{
private static String aPerson;
private String first;
private String middle;
private String last;
private Address address;
private PhoneNumber phone;
public String getFirst()
{
return this.first;
}
public void setFirst(String FirstName)
{
this.first = FirstName;
}
public String getMiddle()
{
return this.middle;
}
public void setMiddle(String MiddleName)
{
this.middle = MiddleName;
}
public String getLast()
{
return this.last;
}
public void setLast(String LastName)
{
this.last = LastName;
}
public Address getMyAddress()
{
return this.address;
}
public void setMyAddress(Address Address)
{
this.address = Address;
}
public PhoneNumber getMyPhoneNum()
{
return this.phone;
}
public void setMyPhoneNum(PhoneNumber Number)
{
this.phone = Number;
}
public Person()
{
aPerson = getFirst() + getMiddle() + getLast() + getMyAddress() +
getMyPhoneNum();
}
public String toString()
{
return aPerson;
}
}
PhoneNumber:
public class PhoneNumber
{
private String number;
private int areaCode = 0;
private int phonePrefix = 0;
private int phoneLineNum = 0;
private int phoneExtension = 0;
public String getNumber()
{
return number;
}
public void setNumber(String Number)
{
number = Number;
}
public int getAreaCode()
{
return areaCode;
}
public void setAreaCode(int AreaCode)
{
areaCode = AreaCode;
}
public int getPrefix()
{
return phonePrefix;
}
public void setPrefix(int Prefix)
{
phonePrefix = Prefix;
}
public int getPhoneLineNumber()
{
return phoneLineNum;
}
public void setLineNum(int PhoneNumber)
{
phoneLineNum = PhoneNumber;
}
public int getExtension()
{
return phoneExtension;
}
public void setExtension(int Extension)
{
phoneExtension = Extension;
}
}
Address:
public class Address
{
private String state;
private String anAddress;
private String address;
private String city;
private int zip = 0;
public String getState()
{
return state;
}
public void setState(String State)
{
state = State;
}
public String getAddress()
{
return address;
}
public void setAddress(String Address)
{
address = Address;
}
public String getCity()
{
return city;
}
public void setCity(String City)
{
city = City;
}
public int getZip()
{
return zip;
}
public void setZip(int Zip)
{
zip = Zip;
}
public Address()
{
anAddress = getState() + getAddress() + getCity() + getZip();
}
public String toString()
{
return this.anAddress;
}
}
Letter:
public class Letter
{
private Person to;
private Person from;
private String body;
private String finishedLetter;
public Person getTo()
{
return to;
}
public void setTo(Person newValue)
{
to = newValue;
}
public Person getFrom()
{
return from;
}
public void setFrom(Person newValue)
{
from = newValue;
}
public String getBody()
{
return body;
}
public void setBody(String newValue)
{
body = newValue;
}
public Letter()
{
finishedLetter = getTo() + " \n" + getFrom() + " \n" + getBody();
}
public String toString()
{
return finishedLetter;
}
}
And main:
public class MainClass
{
public static void main(String args[])
{
PhoneNumber phone1 = new PhoneNumber();
phone1.setAreaCode(417);
phone1.setPrefix(447);
phone1.setLineNum(7533);
phone1.setExtension(0);
PhoneNumber phone2 = new PhoneNumber();
phone2.setAreaCode(210);
phone2.setPrefix(336);
phone2.setLineNum(4343);
phone2.setExtension(9850);
Address address1 = new Address();
address1.setState("MO");
address1.setAddress("1001 East Chestnut Expressway");
address1.setCity("Springfield");
address1.setZip(65807);
Address address2 = new Address();
address2.setState("TX");
address2.setAddress("4800 Calhoun Road");
address2.setCity("Houston");
address2.setZip(77004);
Person person1 = new Person();
person1.setFirst("Shane");
person1.setMiddle("Carroll");
person1.setLast("May");
person1.setMyAddress(address1);
person1.setMyPhoneNum(phone1);
Person person2 = new Person();
person2.setFirst("Ted");
person2.setMiddle("Anthony");
person2.setLast("Nugent");
person2.setMyAddress(address2);
person2.setMyPhoneNum(phone2);
Letter aLetter = new Letter();
aLetter.setTo(person2);
aLetter.setFrom(person1);
aLetter.setBody("This is the body");
System.out.println(aLetter.toString());
}
}
Your Letter constructor is calling methods such as getTo() and getFrom() before those fields have been filled. Don't do this since your finishedLetter String will never be correctly "finished". i.e.,
public Letter()
{
finishedLetter = getTo() + " \n" + getFrom() + " \n" + getBody();
}
will always result in null + "\n" + null + "\n" + null
Perhaps that sort of code should be in the toString() method instead.
When your letter is constructed using new Letter(), it initializes its instance field finishedLetter with several null values. Because to, from, and body haven't yet been set with their corresponding setters, their getters return null, resulting in finishedLetter being equal to "null \nnull \nnull".
To fix this, I one approach is to define the finishedLetter in the toString() method itself. This will both fix the issue and take a more object-oriented approach to the program design.
// remove constructor (if you wish) and finishedLetter field
public String toString() {
return getTo() + " \n" + getFrom() + " \n" + getBody();
}
An even better approach is to require to, from, and body, as parameters in the Letter constructor.
// remove finishedLetter field
public Letter(Person to, Person from, String body) {
this.to = to;
this.from = from;
this.body = body;
}
public String toString() {
return getTo() + " \n" + getFrom() + " \n" + getBody();
}

Categories