I'm currently working on a project which is in Java 4 and I have to sort an ArrayList by 2 values. This is an ArrayList of ClassTest.
public class ClassTest{
String code; // "01", "02" or "03".
String date; // 01/01/2001.
}
My problem is that I have to sort in first by code and after by the closest date of the current date. I'm in Java 4 and I can't use many things I usually used for sorting an Array like Comparator<ClassTest>.
What algorithm can I use that isn't too slow?
Using Comparator interface, without Generics (<..>)
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
public class CollectionSorter {
public static void main(String args[]) {
ClassTest obj1 = new ClassTest();
obj1.setCode("01");
obj1.setDate("2001-02-01");
ClassTest obj2 = new ClassTest();
obj2.setCode("01");
obj2.setDate("2001-01-01");
ClassTest obj3 = new ClassTest();
obj3.setCode("02");
obj3.setDate("2001-01-01");
List list = new ArrayList();
list.add(obj1);
list.add(obj2);
list.add(obj3);
System.out.println("Before sorting - " + list);
Collections.sort(list, new ClassTestComparator());
System.out.println("After sorting - " + list);
}
}
class ClassTest{
private String code; // "01", "02" or "03".
private String date; // 01/01/2001.
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String toString()
{
return "[code: " + code + ", date: " + date + "]";
}
}
class ClassTestComparator implements Comparator {
public int compare(Object o1, Object o2) {
ClassTest obj1 = (ClassTest) o1;
ClassTest obj2 = (ClassTest) o2;
int code1 = Integer.parseInt(obj1.getCode());
int code2 = Integer.parseInt(obj2.getCode());
int result = 0;
if(code1 > code2) {
result = 1;
}
if(code1 < code2) {
result = -1;
}
if (result != 0) {
return result;
}
// Sort by Date ("by the closest date of the current date")
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = null;
Date date2 = null;
try {
date1 = sdf.parse(obj1.getDate());
date2 = sdf.parse(obj2.getDate());
} catch(ParseException e) {
e.printStackTrace();
}
if(date1.compareTo(date2)>0){
result = 1;
}else if(date1.compareTo(date2)<0){
result = -1;
}else if(date1.compareTo(date2)==0){
result = 0;
}
return result;
}
}
Note: The code is tested in Java 1.4 version and works as expected
I don't know if this is possible in your Java-Version, but maybe you can try this way:
public class ClassTest implements Comparable<ClassTest> {
String code; // "01", "02" or "03".
String date; // 01/01/2001.
#Override
public int compareTo(ClassTest ct) {
// Sort by Code
result = code.compateTo(ct.code);
if (result != 0){return result;}
// Sort by Date ("by the closest date of the current date")
result = (...)
return result;
}
}
And then you can just call
Collections.sort(yourArrayListOfClassTest);
Related
I am working on a dummy hospital database. I have an ArrayList that has the combination of all possible times that a doctor can theoretically hold an appointment, and another ArrayList that holds actual registered appointments.
Availability {
int doctorid;
String specialty;
Date date;
int order_of_appointment;
}
//////////
ArrayList<Availability> allTimes;
ArrayList<Availability> busyTimes;
What I want to accomplish is finding the times where doctors are free. Which is the result of (allTimes - busyTimes)
I tried using allTimes.removeAll(busyTimes) but it didn't remove anything.
I made sure that I am overriding the equals() method in the Availability class but it still doesn't remove anything.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Availability)) return false;
Availability that = (Availability) o;
return doctorid == that.doctorid &&
order_of_appointment == that.order_of_appointment &&
Objects.equals(specialty, that.specialty) &&
Objects.equals(date, that.date);
}
Output:
busyTimes =
[Availability{doctorid=1, specialty='internal medicine', date=2021-11-02, order_of_appointment=2}
]
allTimes =
[Availability{doctorid=1, specialty='internal medicine', date=2021-11-02, order_of_appointment=1}
, Availability{doctorid=1, specialty='internal medicine', date=2021-11-02, order_of_appointment=2}
, Availability{doctorid=1, specialty='internal medicine', date=2021-11-02, order_of_appointment=3}]
The output I get for freeTimes is identical to allTimes even though I'm expecting it to remove the appointment with order_of_appointment==2.
I am totally clueless on what might be causing this. Any help would be appreciated. Thanks in advance!
You don't show how are you creating the array, or how are you adding the elements.
I did a simple program with ArrayLists and works as expected:
import java.util.*;
class A {
int id;
A(int id) {
this.id = id;
}
#Override
public boolean equals(Object o) {
return o instanceof A && this.id == ((A)o).id;
}
public String toString() {
return String.format("A{id:%s}", id);
}
public static void main(String ... args) {
List<A> a = new ArrayList<A>(Arrays.asList(new A(1), new A(2)));
List<A> b = new ArrayList<A>(Arrays.asList(new A(2), new A(3)));
a.removeAll(b);
System.out.println(a);
}
}
Output:
[A{id:1}]
What was wrong is that even though I had the date format set up as "yyyy-MM-dd", it still stored the time inside the Date object. I converted the Date objects to strings and then compared the strings and that worked. Thank you all.
You need to override equals(Object obj) method in Availability class with your comparison logic.
I implemented it. please check.
import java.util.Date;
public class Availability {
private int doctorId;
private String specialty;
private Date date;
private int orderOfAppointment;
public Availability() {
super();
}
public Availability(int doctorId, String specialty, Date date, int orderOfAppointment) {
super();
this.doctorId = doctorId;
this.specialty = specialty;
this.date = date;
this.orderOfAppointment = orderOfAppointment;
}
public int getDoctorId() {
return doctorId;
}
public void setDoctorId(int doctorId) {
this.doctorId = doctorId;
}
public String getSpecialty() {
return specialty;
}
public void setSpecialty(String specialty) {
this.specialty = specialty;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public int getOrderOfAppointment() {
return orderOfAppointment;
}
public void setOrderOfAppointment(int orderOfAppointment) {
this.orderOfAppointment = orderOfAppointment;
}
#Override
public String toString() {
return "Availability [doctorId=" + doctorId + ", specialty=" + specialty + ", date=" + date
+ ", orderOfAppointment=" + orderOfAppointment + "]";
}
#Override
public boolean equals(Object obj) {
boolean returnVal = false;
Availability busyslote = (Availability) obj;
if (this.doctorId == busyslote.doctorId && this.orderOfAppointment == busyslote.orderOfAppointment
&& this.specialty.equalsIgnoreCase(busyslote.specialty) && this.date.equals(busyslote.date)) {
returnVal = true;
} else {
returnVal = false;
}
return returnVal;
}
}
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class AppointmentMain {
public static void main(String[] args) {
List<Availability> allAppointment = new ArrayList<>();
List<Availability> attenedAppointment = new ArrayList<>();
Availability obj1 = new Availability(1, "Internal Medicine", new Date(), 1);
Availability obj2 = new Availability(1, "Internal Medicine", new Date(), 2);
Availability obj3 = new Availability(1, "Internal Medicine", new Date(), 3);
allAppointment.add(obj1);
allAppointment.add(obj2);
allAppointment.add(obj3);
Availability obj4 = new Availability(1, "Internal Medicine", new Date(), 3);
attenedAppointment.add(obj4);
System.out.println("Befour count :" + allAppointment.size());
allAppointment.removeAll(attenedAppointment);
System.out.println("After count :" + allAppointment.size());
}
}
I am creating an android application where I need to sort objects according to date. The date is stored as a String in Customer Object. How can I do it?
I have already tried it using the Collection.sort() method but with no success.
public static Comparator<Customer> dateNewOld = new Comparator<Customer>() {
#Override
public int compare(Customer o1, Customer o2) {
DateFormat f = new SimpleDateFormat("dd/MM/yyyy");
try
{
return f.parse(o2.date).compareTo(f.parse(o1.date));
}
catch (ParseException e)
{
e.printStackTrace();
}
return 0;
}
};
I expect the output to be sorted ArrayList but it doesn't get sorted according to date.
My Date Format is 19.Jul.2019, but it’s giving me Unparseable Exception.
java.time
Use the java.time classes that supplant the troublesome legacy classes (java.util.Date, java.sql.Date, SimpleDateFormat). An implementation of the modern classes come with Android 26 and later.
Most of the java.time functionality is back-ported to Java 6 & Java 7 in the ThreeTen-Backport project. Further adapted for earlier Android (<26) in ThreeTenABP. See How to use ThreeTenABP….
LocalDate represents a date-only value, without time-of-day and without time zone.
package sortdates;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class SortDates {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
Comparator<MyData> comparator = Comparator.comparing(myData -> LocalDate.parse(myData.date, formatter));
List<MyData> set = getMyData().stream()
.sorted(comparator)
.collect(Collectors.toList());
set.forEach(myData -> System.out.println(myData.date));
}
private static Collection<MyData> getMyData() {
return Arrays.asList(
new MyData("01/01/2000"),
new MyData("01/02/2000"),
new MyData("03/01/2002"),
new MyData("04/06/2001")
);
}
public static class MyData{
String date;
public MyData(String date) {
this.date = date;
}
}
}
LocalDate as your property
The best solution is to alter your Customer class to use LocalDate class as the type of your property.
Tip: Use a more descriptive name for your member fields that just date.
public class Customer {
public LocalDate firstContact ;
…
}
Now your Comparator becomes quite simple, as the LocalDate class already implements the Comparable interface and its compareTo method.
public static Comparator< Customer > CustomerComparator = new Comparator< Customer >()
{
#Override
public int compare( Customer c1 , Customer c2 ) {
return ( c1.firstContact.compareTo( c2.firstContact ) ) ;
}
};
If you cannot change the data type of your class property, see the correct Answer by Ezequiel.
ArrayList sorting String_Dates and avoiding duplicates on adding.
Adding a new example to #Ezequiel post.
public class ArrayListSet {
static ArrayList<String> list = new java.util.ArrayList<String>();
public static void main(String[] args) {
String inputDatess = "15.10.2020,11.10.2020,12.10.2020,12.10.2020,18.10.2020,13.10.2020,14.10.2020,11.10.2020,"
+ "15.10.2020,15.10.2020,15.10.2020,16.10.2020,17.10.2020,18.10.2020,19.10.2020,20.10.2020,10.10.2020";
String[] dates = inputDatess.split(",");
for (int i = 0; i < dates.length; i++) {
listCustomAdd(dates[i]);
}
System.out.println("ArrayList with Custom Funciton for Add:\n"+list);
ArrayList<String> listSorted = getSortedDatesStrList(list.stream());
System.out.println("Sorted ArrayList:\n"+listSorted);
}
public static ArrayList<String> getSortedDatesStrList(Stream<String> stream) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
Comparator<String> comparator = Comparator.comparing(myData -> LocalDate.parse(myData, formatter));
ArrayList<String> sortedList = (ArrayList<String>) stream
.sorted(comparator)
.collect(Collectors.toList());
return sortedList;
}
public static void listCustomAdd(String dateStr) {
if( !list.contains(dateStr) )
list.add(dateStr);
}
}
Example with Customed ArrayList to sort and avoid duplicates:
public class CustomArrayListSet {
//static ArrayList<String> predefinedList = new java.util.ArrayList<String>();
static ArrayListCustomStr<String> customList = new ArrayListCustomStr<String>();
public static void main(String[] args) {
String inputDatess = "15.10.2020,11.10.2020,12.10.2020,12.10.2020,18.10.2020,13.10.2020,14.10.2020,11.10.2020,"
+ "15.10.2020,15.10.2020,15.10.2020,16.10.2020,17.10.2020,18.10.2020,19.10.2020,20.10.2020,10.10.2020";
String[] dates = inputDatess.split(",");
for (int i = 0; i < dates.length; i++) {
customList.add(dates[i]);
}
System.out.println("Custom ArrayList with override Add Function:\n"+customList);
customList.sortDatesStrList();
System.out.println("Sorted ArrayList:\n"+ customList );
}
}
class ArrayListCustomStr<T> implements Set<T> {
#Override
public String toString() {
StringBuffer buffer = new StringBuffer("[");
for (int i = 0; i < entries.size(); i++) {
buffer.append(entries.get(i));
if ( (i+1) < entries.size() ) buffer.append(", ");
}
buffer.append("]");
return buffer.toString();
}
public void sortDatesStrList() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
Comparator<String> comparator = Comparator.comparing(myData -> LocalDate.parse(myData, formatter));
ArrayList<String> sortedList = (ArrayList<String>) entries.stream()
.sorted(comparator)
.collect(Collectors.toList());
entries = sortedList;
}
private ArrayList<String> entries;
// Simple constructor using an array list for its entries.
public ArrayListCustomStr() {
super();
entries = new ArrayList<String>();
}
public int size() {
return entries.size();
}
public void clear() {
entries.clear();
}
public boolean isEmpty() {
return entries.isEmpty();
}
public Object[] toArray() {
return entries.toArray();
}
public boolean add(Object o) {
// Ignore existing entries to ensure Set interface contract
if (entries.contains(o))
return false;
return entries.add((String) o);
}
public boolean contains(Object o) {
return entries.contains(o);
}
public boolean remove(Object o) {
return entries.remove(o);
}
#SuppressWarnings("unchecked")
public boolean addAll(#SuppressWarnings("rawtypes") Collection c) {
return entries.addAll(c);
}
public boolean containsAll(#SuppressWarnings("rawtypes") Collection c) {
return entries.containsAll(c);
}
public boolean removeAll(#SuppressWarnings("rawtypes") Collection c) {
return entries.removeAll(c);
}
public boolean retainAll(#SuppressWarnings("rawtypes") Collection c) {
return entries.retainAll(c);
}
#SuppressWarnings("unchecked")
public Iterator<T> iterator() {
return (Iterator<T>) entries.iterator();
}
#SuppressWarnings("unchecked")
public Object[] toArray(Object[] a) {
return entries.toArray(a);
}
}
As per mkyong
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = sdf.parse("2009-12-31");
Date date2 = sdf.parse("2010-01-31");
System.out.println("date1 : " + sdf.format(date1));
System.out.println("date2 : " + sdf.format(date2));
if (date1.compareTo(date2) > 0) {
System.out.println("Date1 is after Date2");
}
Comparing o2 with o1 will sort your list in descending order.
You can use Collections.sort() as well as list.sort()
I have created a test class with a customer object.
Hope this example will help.
package project;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class SortTest
{
public static void main(String args[])
{
List<Customer> list = new ArrayList<>();
list.add( new Customer( 1, "21/07/2019" ) );
list.add( new Customer( 2, "19/06/2019" ) );
list.add( new Customer( 3, "20/07/2019" ) );
Collections.sort( list, dateNewOld );
//list.sort( dateNewOld );
print( list );
}
public static Comparator<Customer> dateNewOld = new Comparator<Customer>()
{
#Override
public int compare( Customer o1, Customer o2 )
{
DateFormat f = new SimpleDateFormat( "dd/MM/yyyy" );
try
{
return f.parse( o2.date ).compareTo( f.parse( o1.date ) );
}
catch ( ParseException e )
{
e.printStackTrace();
}
return 0;
}
};
private static void print( List<Customer> list )
{
for ( Customer customer : list )
{
System.out.println(customer);
}
}
static class Customer
{
final int id;
final String date;
Customer( int id, String date )
{
this.id = id;
this.date = date;
}
#Override
public String toString()
{
return "Customer{" +
"id=" + id +
", date='" + date + '\'' +
'}';
}
}
}
I guess the problem is with how you compare the two Strings, here is a working example(in ascending order).
List<String> dateList = new ArrayList<>();
dateList.add("22/05/1995");
dateList.add("22/01/1995");
dateList.add("22/01/1994");
Comparator<String> dateNewOld = new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
DateFormat f = new SimpleDateFormat("dd/MM/yyyy");
try {
return f.parse(o1).compareTo(f.parse(o2));
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
};
dateList.sort(dateNewOld);
System.out.println(dateList);
PS: My guess is that your code is not sorting because of return 0 inside the comparator. Maybe your code is throwing an exception and you haven't seen console!
Eclipse can auto-generate a toString() method from a object's fields. If those fields are objects then they too may have similarly auto-generated toString() methods.
e.g. a President object might look like this:
President [country=USA, name=Name [title=Mr, forename=Barack, surname=Obama], address=Address [houseNumber=1600, street=Pennsylvania Avenue, town=Washington]]
which is easier to read if I format it:
President [
country=USA,
name=Name [
title=Mr,
forename=Barack,
surname=Obama],
address=Address [
houseNumber=1600,
street=Pennsylvania Avenue,
town=Washington]]
What is the best way to parse this String to create a map of maps?
I've got a solution, but it's not pretty. I was hoping to be able to avoid the low level String manipulation somehow, but here it is:
import java.util.LinkedHashMap;
import java.util.Map;
public class MappedObject {
public String className;
public Map<String, String> leafFields = new LinkedHashMap<>();
public Map<String, MappedObject> treeFields = new LinkedHashMap<>();
#Override
public String toString() {
return "[className=" + className
+ (leafFields.isEmpty() ? "" : ", leafFields=" + leafFields)
+ (treeFields.isEmpty() ? "" : ", treeFields=" + treeFields)
+ "]";
}
public static MappedObject createFromString(String s) {
MappedObject mo = new MappedObject();
new Mapper(s).mapObject(mo);
return mo;
}
private static class Mapper {
private String s;
public Mapper(String s) {
this.s = s;
}
private String mapObject(MappedObject mo) {
mo.className = removeFirstNCharacters(s.indexOf(' '));
while (s.contains("=")) {
removeLeadingNonLetters();
String key = removeFirstNCharacters(s.indexOf('='));
removeFirstNCharacters(1); // remove the =
String leafValue = getLeafValue();
if (leafValue != null) {
mo.leafFields.put(key, leafValue);
if (s.startsWith("]")) { // that was the last field in the tree
return s;
}
} else {
MappedObject treeField = new MappedObject();
mo.treeFields.put(key, treeField);
s = new Mapper(s).mapObject(treeField);
}
}
return s; // s contains only close brackets - ]
}
private void removeLeadingNonLetters() {
int i = 0;
while (!Character.isLetter(s.charAt(i))) {
i++;
}
removeFirstNCharacters(i);
}
private String removeFirstNCharacters(int n) {
String value = s.substring(0, n);
s = s.substring(value.length());
return value;
}
private String getLeafValue() {
int endIndex = getEndIndex();
if (!s.contains("[") || s.indexOf('[') > endIndex) {
return removeFirstNCharacters(endIndex);
}
return null;
}
/** The end of the value, if it's a leaf field. */
private int getEndIndex() {
if(s.contains(",")) {
return Math.min(s.indexOf(','), s.indexOf(']'));
}
return s.indexOf(']');
}
}
}
I am attempting to write a program that will output data received from a csv file. The CSV file is composed of 28 or so strings/lines with each data in the line separated by a comma into 5 categories (Team name, League, Coaches, Division and Full Time).
I actually have a couple of issues...
When i run my program, i receive a random sequence of characters (such as: [Ljava.lang.String;#5e34d46a) in my coaches category instead of a name that i am expecting. Does this have something to do with it being in an array? How would i solve it.
The categories for each string are displayed in the output as a list, i would like to output the data of strings into a line. For example, instead of the output displaying:
Team name: Team A
League: Western Conference
Coaches: [Ljava.lang.String;#1c751d58
Division: 2
Full Time: true
I would like it to be displayed as a line.
The last category of a single instance of a string in the output is attached to the first category of the next string. Like so: Full Time: trueTeam name: Team A. How would i separate this?
My Team.java code:
public class Team
{
private String name;
private String league;
private String[] coaches;
private String division;
private boolean fullTime;
public Team(String dataLine)
{
String[] data = dataLine.split(",");
this.name = data[0];
this.coaches = getStringAsArray(data[1], ":");
this.league = data[2];
this.division = data[3];
this.fullTime = data[4].equals("yes");
}
public Team(){
}
private String[] getStringAsArray(String t, String delimiter)
{
String[] result = t.split(delimiter);
return result;
}
private String getArrayAsString(String[] coaches)
{
coaches = this.getCoaches();
String result = "";
for(int i = 0; i<coaches.length; i++)
{
result += coaches[i] +" ";
}
result = result.trim();
return result;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
public void setCoaches(String coaches)
{
this.coaches = getStringAsArray(coaches, ":");
}
public String getCoachesAsString()
{
String result = getArrayAsString(coaches);
return result;
}
public boolean isFullTime() {
return fullTime;
}
public void setFullTime(boolean fullTime) {
this.fullTime = fullTime;
}
public String getDivision() {
return division;
}
public void setDivision(String division) {
this.division = division;
}
public String[] getCoaches() {
return coaches;
}
public void setCoaches(String[] coaches) {
this.coaches = coaches;
}
public String getLeague() {
return league;
}
public void setLeague(String league) {
this.league = league;
}
#Override
public String toString() {
return "Team name: " + name + "\nLeague: " + this.league + "\nCoaches: " + this.coaches + "\nDivision: " + this.division + "\nFull Time: " + this.fullTime;
}
}
My StoreData.java code:
import shiftershape.model.Team;
import java.util.ArrayList;
public class StoreData {
public static ArrayList<Team> teams = new ArrayList<Team>();
public static String getTeams()
{
String s = "";
for(int i = 0; i < teams.size(); i++){
s += teams.get(i);
}
return s;
}
public static ArrayList<Team> TeamListFromArray(String[] as)
{
ArrayList<Team> teams = new ArrayList<Team>();
// for( int i= 0 ; i < as.length; i++){
for (String s: as){
teams.add(new Team(s));
}
return teams;
}
}
My ReadCSV.java code:
import Utilities.StoreData;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import shiftershape.model.Team;
public class ReadCsv {
public void readCsv() {
String csvFileToRead = "C:/Users/Fryyy/Desktop/FootballRepo/TestData/football_teams_phase1.csv";
BufferedReader br = null;
String line = "";
try {
br = new BufferedReader(new FileReader(csvFileToRead));
int i = 0;
while ((line = br.readLine()) != null) {
Team one = new Team(line);
if(i > 0){
StoreData.teams.add(new Team(line));
}else{
i++;
}
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static ArrayList<Team> getTeams() {
return StoreData.teams;
}
public static void setTeams(ArrayList<Team> teams) {
StoreData.teams = teams;
}
}
My FootballC.java code:
import Utilities.StoreData;
import shiftershape.model.Team;
public class FootballC {
public static void main(String[] args)
{
ReadCsv junk = new ReadCsv();
junk.readCsv();
System.out.println(StoreData.getTeams());
}
}
System.out.println(StoreData.getTeams()); will call toString() on String[]
try this:
for (String s : StoreData.getTeams()) {
System.out.println(s);
}
[Ljava.lang.String;#5e34d46a) is the resource code for an object when printed to standard out. In this case being a string, so somewhere it looks like you're printing an array instead of the value within the array, causing the resource ID to be shown instead of the values within, as Java doesn't print array contents by default.
[Ljava.lang.String;#1c751d58 is the String version of an array. Arrays don't have a nice toString() method. If you used Lists in stead of Arrays it will print better.
The quick conversion of an array to a list is Arrays.asList(array);
Output of below class is :
size is 3
size is 1
But if I change the TreeSet to a HashSet so line :
Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();
becomes
Set<SuggestionDetailBean> set = new HashSet<SuggestionDetailBean>();
the output is :
size is 3
size is 2
Shout using HashSet or TreeSet not change the size of Set ?
Using HashSet seems to behave as expected because it is removing duplicates but when I use TreeSet the duplicates remain ?
I think the hashcode and equals methods in SuggestionDetailBean are overriden correctly ?
Here is the code :
public class TestSet {
public static void main(String args[]){
SuggestionDetailBean s = new SuggestionDetailBean();
s.setTagList("teddst");
s.setUrl("testurl");
SuggestionDetailBean s2 = new SuggestionDetailBean();
s2.setTagList("teddst");
s2.setUrl("testurl");
SuggestionDetailBean s3 = new SuggestionDetailBean();
s3.setTagList("tessdafat");
s3.setUrl("fdfaasdfredtestur ldd");
List<SuggestionDetailBean> list = new ArrayList<SuggestionDetailBean>();
list.add(s);
list.add(s2);
list.add(s3);
Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();
set.addAll(list);
System.out.println("size is "+list.size());
System.out.println("size is "+set.size());
}
}
public class SuggestionDetailBean implements Comparable<Object> {
private String url;
private String tagList;
private String numberOfRecommendations;
private String date;
private String time;
private String summary;
private String truncatedUrl;
public void setTruncatedUrl(String truncatedUrl) {
if(truncatedUrl.length() > 20){
truncatedUrl = truncatedUrl.substring(0, 20)+"...";
}
this.truncatedUrl = truncatedUrl;
}
public String getSummary() {
if(summary == null){
return "";
}
else {
return summary;
}
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTime() {
return time;
}
public String getTruncatedUrl() {
return this.truncatedUrl;
}
public void setTime(String time) {
this.time = time;
}
public String getTagList() {
if(tagList == null){
return "";
}
else {
return tagList;
}
}
public void setTagList(String tagList) {
this.tagList = tagList;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getNumberOfRecommendations() {
return numberOfRecommendations;
}
public void setNumberOfRecommendations(String numberOfRecommendations) {
this.numberOfRecommendations = numberOfRecommendations;
}
#Override
public int compareTo(Object o) {
DateFormat formatter;
Date date1 = null;
Date date2 = null;
SuggestionDetailBean other = (SuggestionDetailBean) o;
if(this.date == null || other.date == null){
return 0;
}
formatter = new SimpleDateFormat(SimpleDateFormatEnum.DATE.getSdfType()+" "+SimpleDateFormatEnum.TIME.getSdfType());
try {
date1 = (Date) formatter.parse(this.date + " " + this.time);
date2 = (Date) formatter.parse(other.date + " " + other.time);
} catch (ParseException e) {
System.out.println("Exception thrown in"+this.getClass().getName()+", compareTo method");
e.printStackTrace();
}
catch(NullPointerException npe){
System.out.println("Exception thrown "+npe.getMessage()+" date1 is "+date1+" date2 is "+date2);
}
return date2.compareTo(date1);
}
#Override
public int hashCode() {
return this.url.hashCode();
}
#Override
public boolean equals(Object obj) {
SuggestionDetailBean suggestionDetailBean = (SuggestionDetailBean) obj;
if(StringUtils.isEmpty(this.getTagList())){
return this.getUrl().equals(suggestionDetailBean.getUrl());
}
else {
return (this.getTagList().equals(suggestionDetailBean.getTagList())) &&
(this.getUrl().equals(suggestionDetailBean.getUrl()));
}
}
}
Edit :
Note : if I convert the hashset to a treeset using :
Set<SuggestionDetailBean> sortedSet = new TreeSet<SuggestionDetailBean>(hashset);
Then correct sorting is maintained, as the removal of duplicates is based on the object hashcode and equals methods not the compareto method.
According to the Javadoc for TreeSet:
Note that the ordering maintained by a set (whether or not an explicit
comparator is provided) must be consistent with equals if it is to
correctly implement the Set interface. (See Comparable
or Comparator for a precise definition of consistent with
equals.) This is so because the Set interface is defined in
terms of the equals operation, but a TreeSet instance
performs all element comparisons using its compareTo (or
compare) method, so two elements that are deemed equal by this method
are, from the standpoint of the set, equal. The behavior of a set
is well-defined even if its ordering is inconsistent with equals; it
just fails to obey the general contract of the Set interface.
So, the problem is with your compareTo method: either it's giving inconsistent results, or else it's giving consistent results that don't obey the rule that a.compareTo(b) == 0 if and only if a.equals(b).
For example, this bit:
if(this.date == null || other.date == null){
return 0;
}
means "if either this or other has date == null, then report that this and other are equal", which is certainly not what you want.