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.
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 have this class that implements Cloneable. I only need a shallow copy here. Can anyone point to what is wrong with the java compliance here.
public class EventSystem implements Cloneable{
private String enrollmentId;
private String requestId;
private String tokenId;
private Date eventAt;
private Date loggedAt;
private String appCardId;
private String fieldKey;
private String fieldValue;
private String trsDimCardIssuerId;
private String trsDimCardProductId;
private String trsDimAppEventLocationId;
private String trsDimPaymentNetworkId;
private String trsDimAppCardTypeId;
private String trsTempLogId;
public Date getEventAt() {
return eventAt;
}
public void setEventAt(Date eventAt) {
this.eventAt = eventAt;
}
public Date getLoggedAt() {
return loggedAt;
}
public void setLoggedAt(Date loggedAt) {
this.loggedAt = loggedAt;
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public String getEnrollmentId() {
return enrollmentId;
}
public void setEnrollmentId(String enrollemntId) {
this.enrollmentId = enrollemntId;
}
public String getTokenId() {
return tokenId;
}
public void setTokenId(String tokenId) {
this.tokenId = tokenId;
}
public String getTrsDimCardIssuerId() {
return trsDimCardIssuerId;
}
public void setTrsDimCardIssuerId(String trsDimCardIssuerId) {
this.trsDimCardIssuerId = trsDimCardIssuerId;
}
public String getTrsDimCardProductId() {
return trsDimCardProductId;
}
public void setTrsDimCardProductId(String trsDimCardProductId) {
this.trsDimCardProductId = trsDimCardProductId;
}
public String getTrsDimAppEventLocationId() {
return trsDimAppEventLocationId;
}
public void setTrsDimAppEventLocationId(String trsDimAppEventLocationId) {
this.trsDimAppEventLocationId = trsDimAppEventLocationId;
}
public String getTrsDimPaymentNetworkId() {
return trsDimPaymentNetworkId;
}
public void setTrsDimPaymentNetworkId(String trsDimPaymentNewtorkId) {
this.trsDimPaymentNetworkId = trsDimPaymentNewtorkId;
}
public String getTrsDimAppCardTypeId() {
return trsDimAppCardTypeId;
}
public void setTrsDimAppCardTypeId(String trsDimAppCardTypeId) {
this.trsDimAppCardTypeId = trsDimAppCardTypeId;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
#Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getTrsTempLogId() {
return trsTempLogId;
}
public void setTrsTempLogId(String trsTempLogId) {
this.trsTempLogId = trsTempLogId;
}
public String getAppCardId() {
return appCardId;
}
public void setAppCardId(String appCardId) {
this.appCardId = appCardId;
}
public String getFieldKey() {
return fieldKey;
}
public void setFieldKey(String fieldKey) {
this.fieldKey = fieldKey;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
}
Is there a problem with String copy here.
Your String fields aren't a problem. Your Date fields are.
When you clone an EventSystem instance, each of its fields points to exactly the same object as source object’s corresponding field. Thus, a cloned instance’s enrollmentId field points to the same String object as the original instance’s enrollmentId.
But that’s perfectly okay. You can safely share String objects, because they’re immutable. A String object cannot be altered. You can change value of a field which holds a String, but the String object itself can never change.
However, Date objects can be changed. This means the clone is not truly independent of the source instance. They both refer to the same mutable object, so if that object is changed for just one of the two EventSystem instances, both instances will see the changes, which can lead to some insidious bugs. Consider this code:
Calendar calendar = Calendar.getInstance();
calendar.set(1969, Calendar.JULY, 20, 22, 56, 0);
Date moonLanding = calendar.getTime();
EventSystem e1 = new EventSystem();
e1.setEventAt(moonLanding);
// Prints Sun Jul 20 22:56:00 EDT 1969
System.out.println(e1.getEventAt());
EventSystem e2 = (EventSystem) e1.clone();
// Both e1 and e2 have references to the same Date object, so changes
// to that Date object are seen in both objects!
e2.getEventAt().setTime(System.currentTimeMillis());
// You might expect these to be different, since we only changed
// e2.getEventAt(), but they're the same.
System.out.println(e1.getEventAt());
System.out.println(e2.getEventAt());
One way to resolve this is to use a common object-oriented technique known as defensive copying:
public Date getEventAt() {
return (eventAt != null ? (Date) eventAt.clone() : null);
}
public void setEventAt(Date eventAt) {
this.eventAt = (eventAt != null ? (Date) eventAt.clone() : null);
}
public Date getLoggedAt() {
return (loggedAt != null ? (Date) loggedAt.clone() : null)
}
public void setLoggedAt(Date loggedAt) {
this.loggedAt = (loggedAt != null ? (Date) loggedAt.clone() : null);
}
This prevents any other classes from directly modifying the internal Date field.
Another, less safe option is to clone the Date fields in your clone method:
#Override
public Object clone() throws CloneNotSupportedException {
EventSystem newInstance = (EventSystem) super.clone();
if (newInstance.eventAt != null) {
newInstance.eventAt = (Date) newInstance.eventAt.clone();
}
if (newInstance.loggedAt != null) {
newInstance.loggedAt = (Date) newInstance.loggedAt.clone();
}
return newInstance;
}
This is my VO
public class SomeVO {
private String name;
private String usageCount;
private String numberofReturns;
private String trendNumber;
private String nonTrendNumber;
private String trendType;
private String auditType;
public SomeVO(String name,String usageCount,String numberofReturns,String trendNumber,String nonTrendNumber,String trendType,String auditType){
this.name = name;
this.usageCount = usageCount;
this.numberofReturns = numberofReturns;
this.trendNumber = trendNumber;
this.nonTrendNumber = nonTrendNumber;
this.trendType = trendType;
this.auditType = auditType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsageCount() {
return usageCount;
}
public void setUsageCount(String usageCount) {
this.usageCount = usageCount;
}
public String getNumberofReturns() {
return numberofReturns;
}
public void setNumberofReturns(String numberofReturns) {
this.numberofReturns = numberofReturns;
}
public String getTrendNumber() {
return trendNumber;
}
public void setTrendNumber(String trendNumber) {
this.trendNumber = trendNumber;
}
public String getNonTrendNumber() {
return nonTrendNumber;
}
public void setNonTrendNumber(String nonTrendNumber) {
this.nonTrendNumber = nonTrendNumber;
}
public String getTrendType() {
return trendType;
}
public void setTrendType(String trendType) {
this.trendType = trendType;
}
public String getAuditType() {
return auditType;
}
public void setAuditType(String auditType) {
this.auditType = auditType;
}
}
Here is my values
List<SomeVO> myList = new ArrayList<SomeVO>();
SomeVO some = new SomeVO("A","0","0","123","123","Trend","AuditX");
myList.add(some);
some = new SomeVO("B","1","1","234","234","Non trend","AuditX");
myList.add(some);
some = new SomeVO("C","0","2","345","345","Trend","AuditX");
myList.add(some);
some = new SomeVO("D","2","3","546","546","Trend","AuditX");
myList.add(some);
some = new SomeVO("E","2","4","678","678","Non trend","AuditX");
myList.add(some);
some = new SomeVO("F","0","0","123","123","Non trend","AuditA");
myList.add(some);
some = new SomeVO("G","0","0","123","123","Trend","AuditB");
myList.add(some);
Here is my comparator
public String currentAudit = "AuditX";
public class AuditComparator implements Comparator<SomeVO> {
#Override
public int compare(SomeVO o1, SomeVO o2) {
if(currentAudit.equalsIgnoreCase(o1.getAuditType()) && currentAudit.equalsIgnoreCase(o2.getAuditType())) {
int value1 = o2.getUsageCount().compareTo(o1.getUsageCount());
if (value1 == 0) {
int value2 = o1.getNumberofReturns().compareTo(o2.getNumberofReturns());
if(o1.getTrendType().equalsIgnoreCase("Trend") && o2.getTrendType().equalsIgnoreCase("Trend")) {
if (value2 == 0) {
return o1.getTrendNumber().compareTo(o2.getTrendNumber());
} else {
return value2;
}
} else {
if (value2 == 0) {
return o1.getNonTrendNumber().compareTo(o2.getNonTrendNumber());
} else {
return value2;
}
}
}
return value1;
} else {
return 1;
}
}
}
I am trying to sort the VO based on below conditions
First only set of values of currentAudit should be taken in to
consideration i.e., AuditX
a) then it should be sorted with
Usage count in descending order
b) if same usage count found then it
should be sorted with Return count in ascending order
c) if same
return count then it should check for trendType, if trendType
="Trend" then it should sort with Trend number otherwise nonTrend number.
then it should consider rest all auditType's and sorted with
a),b),c) condition as like currentAudit. I tried achieving it and i
ended up with only above comparator. Expected result: D, A, C, E,
F, G. But i get G,F,D,E,B,A,C. Please help me to update the
comparator above.
Your comparator does not meet a simple condition: it is not stateless. A following should always be true: A>B => B<A. In your case, in some scenarios A>B and B>A.
I resolved it by splitting the actual list in to 2 list based on AuditX and rest in another list. Then used below comparator one by one, and then merged in to a result list. Works good.
for(SomeVO some:myList) {
if(some.getAuditType().equalsIgnoreCase("AuditX")) {
auditX.add(some);
} else {
auditY.add(some);
}
}
Collections.sort(auditX, new AuditComparator());
Collections.sort(auditY, new AuditComparator());
public class AuditComparator implements Comparator<SomeVO> {
#Override
public int compare(SomeVO o1, SomeVO o2) {
int value1 = o2.getUsageCount().compareTo(o1.getUsageCount());
if (value1 == 0) {
int value2 = o1.getNumberofReturns().compareTo(o2.getNumberofReturns());
if (value2 == 0) {
return (o1.getTrendType().equalsIgnoreCase("Trend") && o2.getTrendType().equalsIgnoreCase("Trend")) ?
o1.getTrendNumber().compareTo(o2.getTrendNumber()):o1.getNonTrendNumber().compareTo(o2.getNonTrendNumber());
} else {
return value2;
}
}
return value1;
}
The return 1 at the bottom of the comparator makes a bug.
The comparator shall only return 1 if the second element is bigger than the first one, but if they're different, you always return 1, so the very first sorting criteria will be messy.
// a helper for case insensitive comparison
private int compareIgnoreCase(String o1,String o2) {
return o1.toLowercase.compareTo(o2.toLowercase());
}
#Override
public int compare(SomeVO o1, SomeVO o2) {
int result=compareIgnoreCase(o1.getAuditType(),o2.getAuditType());
if (result==0) {
// we need to go to the 2nd criteria
result=o2.getUsageCount().compareTo(o1.getUsageCount());
}
if (result==0) {
// ok, 1st and 2nd criteria was the same, go to the 3rd
result=o1.getNumberofReturns().compareTo(o2.getNumberofReturns());
}
if (result==0) {
// check trends
...
}
return result;
}
I found that this representation of multiple comparison criteria makes the code much easier to follow. We first do the highest priority of comparison, and go on with further comparions if the previous comparisons returned that the two elements are the same (i.e. result is still zero).
In case you need to make a descending sorting at some level, simply put a -, e.g.:
result=-o1.something.compareTo(o2.something)
It is a good idea to have only one exit point in a method (this also makes easier to follow what is happening).
I have a simple loop that checks for any duplicate results,
where studresults holds my results , result is the object result given to the method and r is the current object from the array.
I have been using this method successfully throughout the program although it is not working in this case even though when I debug result and r , are exactly the same does anyone know why this might be? I have tried #Override already as suggested in other answers to no avail.
I am trying to stop duplicated array elements by throwing an exception.
for(Result r : studresults)
{
if(r.equals(result))
{
return false;
}
}
EDIT OK HERE IS THE WHOLE CLASS>
package ams.model;
import java.util.ArrayList;
import java.util.Arrays;
import ams.model.exception.EnrollmentException;
public abstract class AbstractStudent implements Student {
private int studentId;
private String studentName;
private ArrayList<Course> studcourses = new ArrayList<Course>();
private ArrayList<Result> studresults = new ArrayList<Result>();
public AbstractStudent(int studentId, String studentName) {
this.studentId = studentId;
this.studentName = studentName;
}
public String getFullName() {
return studentName;
}
public int getStudentId() {
return studentId;
}
public Result[] getResults() {
Result[] res = studresults.toArray(new Result[0]);
if(res.length > 0 )
{
return res;
}
return null;
}
public boolean addResult(Result result)
{
for(Result r : studresults)
{
if(r.equals(result))
{
return false;
}
}
studresults.add(result);
return true;
}
public void enrollIntoCourse(Course c)
{
//for re-enrollment
if(studcourses.contains(c))
{
studcourses.remove(c);
studresults.clear();
}
studcourses.add(c);
}
public void withdrawFromCourse(Course c) throws EnrollmentException
{
if(studcourses.size() > 0)
{
studcourses.remove(c);
}
else
throw new EnrollmentException();
}
public Course[] getCurrentEnrolment()
{
return studcourses.toArray(new Course[0]);
}
public abstract int calculateCurrentLoad();
public int calculateCareerPoints() {
// TODO Auto-generated method stub
return 0;
}
public String toString()
{
return studentId + ":" + studentName +":" + calculateCurrentLoad();
}
}
Do you already override hashCode method in Result?
If you override equals, you have to override the hashCode method also to allow you return the same hashcode for the similar objects (objects which has the same value but actually different object instances).
I think the default implementation of hashcode will returns different value for a different object instances even though they have the same values.
Instead I converted toString and then compared and it works???
Makes me think there was something slightly unidentical before?
New method
public boolean addResult(Result r)
{
for (Result s : studresults)
{
String sr1 = s.toString();
String sr2 = r.toString();
if(sr1.equals(sr2))
{
return false;
}
}
I'm trying to create a Manga app for Android where the each Chapter has its own Title,Publication Date, Description, etc. And each of said chapters belongs to a Manga object. Which would be a collection of Chapters and would include a list of the titles plus the Title of the Manga itself and the author('s) name(s). The data itself would be parsed from different webpages (but that's another mater).
My confusion is about the class declarations. (i.e. implements, extends)
Ive tried many things but as of right now my code consists of having chapters as an inner class like so:
public abstract class Manga implements MangaList {
public String name;
public String author;
public int chapters;
// names of the XML tags
static final String CHANNEL = "channel";
static final String PUB_DATE = "pubDate";
static final String DESCRIPTION = "description";
static final String LINK = "link";
static final String TITLE = "title";
static final String ITEM = "item";
private final URL feedUrl;
protected Manga(String feedUrl){
try {
this.feedUrl = new URL(feedUrl);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
protected InputStream getInputStream() {
try {
return feedUrl.openConnection().getInputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
List<Chapter> Chapter;
public class Chapter implements Comparable<Chapter> {
final SimpleDateFormat FORMATTER =
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
private String title;
private URL link;
private String description;
private Date date;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title.trim();
}
// getters and setters omitted for brevity
public URL getLink() {
return link;
}
public void setLink(String link) {
try {
this.link = new URL(link);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description.trim();
}
public String getDate() {
return FORMATTER.format(this.date);
}
public void setDate(String date) {
// pad the date if necessary
while (!date.endsWith("00")){
date += "0";
}
date = "";
try {
this.date = FORMATTER.parse(date.trim());
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public Chapter copy(){
Chapter copy = new Chapter();
copy.title = title;
copy.link = link;
copy.description = description;
copy.date = date;
return copy;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Title: ");
sb.append(title);
sb.append('\n');
sb.append("Date: ");
sb.append(this.getDate());
sb.append('\n');
sb.append("Link: ");
sb.append(link);
sb.append('\n');
sb.append("Description: ");
sb.append(description);
return sb.toString();
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((date == null) ? 0 : date.hashCode());
result = prime * result
+ ((description == null) ? 0 : description.hashCode());
result = prime * result + ((link == null) ? 0 : link.hashCode());
result = prime * result + ((title == null) ? 0 : title.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;
Chapter other = (Chapter) obj;
if (date == null) {
if (other.date != null)
return false;
} else if (!date.equals(other.date))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (link == null) {
if (other.link != null)
return false;
} else if (!link.equals(other.link))
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
public int compareTo(Chapter another) {
if (another == null) return 1;
// sort descending, most recent first
return another.date.compareTo(date);
}
}
My question is if this is an appropriate format or if there is a simpler way to create a List of Mangas, each with its own set of Chapters?
EDIT: I've looked it up and decided that using an SQLite Database would be a much simpler way to keep track of the large amount of data I will be parsing.
This way I can maintain two databases. One for Manga titles and authors, and another for the chapters and relevant information. The Related chapters will be linked to the Manga in each table through a reference ID.
I definitely think that there is an easier way to do this; however, it really depends on what you overall goal is. If you are trying to display this in a list you might consider using ListView, but if you are just using the data for content, then you can probably do something similar to what you have. Ultimately, you need to figure out what you are going to do with the app, then you can figure out the easiest way to implement it. Remember though: easier isn't always better. Try and think long term about your project as in who is going to be maintaining this, is it going to grow or shrink, and whether you will add features.
As for extends and implements they are subclasses and interfaces, respectively and has different rules regarding it and more information can be found here: http://docs.oracle.com/javase/tutorial/java/concepts/interface.html
Best of luck!