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!
Related
Ok, so I've got a method which adds elements to a list but it is always throwing my custom exception, no matter what, even when there are no elements in the Set I made.
private Set<Plan> planSet = new HashSet<Plan>();
public Plan createPlan(String name) throws DuplicatePlan{
Plan plan = new Plan(name);
if(!planSet.contains(plan)){
planSet.add(plan);
} else {
throw(new DuplicatePlan("Error, duplicate plan"));
}
return plan;
}
I'm thinking that my equals() and hashCode() methods are causing this. Currently I'm using the default overridden Eclipse hashCode() and equals(), this is what I've got there:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.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;
}
Plan other = (Plan) obj;
if (name == null) {
if (other.name != null){
return false;
}
} else if (!name.equals(other.name)){
return false;
}
return true;
}
This is what Plan does:
private String name;
private Set<Tables> tablesSet;
public Plan(String name){
this.name = name ;
}
Here's what's supposed to happen if a user sets the same name in the TextField:
newPlan.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent action){
if(!newPlan.getText().isEmpty()){
try {
String name = planName.getText();
plan.createPLan(name);
esquema = esquemas.createPlan(planName.getText());
optionsPlans.getItems().add(plan.getName());
} catch (DuplicatePlan e) {
dialog.errorDialog(planError, duplicate);
}
} else {
dialog.errorDialog(empty, emptySpace);
}
}
});
Had to use Answer because it was too long for comment.
This here looks suspicious to me:
String name = planName.getText();
plan.createPLan(name);
esquema = esquemas.createPlan(planName.getText());
I.e. what's up with createPLan and createPlan? Copy & paste error? Or are you calling the same method twice (which would explain the behavior)?
I have an exam and this was in the mock and im not quite sure how to go about it, this isn't homework its simply trying to understand how to do it. Thanks.
public class Book{
private final String title;
private final String author;
private final int edition;
private Book(String title, String author, int edition)
{
this.title = title;
this.author = author;
this.edition = edition;
}
public String getTitle()
{
return title;
}
public String getAuthor()
{
return author;
}
public String getEdition()
{
return edition;
}
}
I need to provide implementations of equals, hashCode and compareTo methods for the above code.
I'm not to sure how to go about it, would it be somthing similar to this for the compareTo method?
title.compareTo(title);
author.compareTo(author);
edition.compareTo(edition);
Thanks, any help would be greatly appreciated.
your compareTo should be this:
title.compareToIgnoreCase(otherTitle);
...
equals:
if(null == title || null == author || null == editor)
{
return false;
}
if(!title.equals(otherTitle)
{
return false;
}
if(!author.equals(otherAuthor)
{
return false;
}
if(!editor.equals(otherEditor)
{
return false;
}
return true;
Take look at this.
http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/builder/package-summary.html
You can use the builders in this package to create default implementations.
IDEs like Eclipse can generate hashCode and equals methods for you (Source -> generate hashCode() and equals()). You can even specify which fields of the object need to match for it to be considered "equal".
For instance here is what Eclipse generates for your class:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((author == null) ? 0 : author.hashCode());
result = prime * result + edition;
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;
Book other = (Book) obj;
if (author == null) {
if (other.author != null)
return false;
} else if (!author.equals(other.author))
return false;
if (edition != other.edition)
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
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.
I am sorting collection wrt date as follows but in collection some date field are empty and it is not sorting correctly.
public class DateComparator implements Comparator<MyList>{
private static boolean isAscending;
private static final String TAG = "DateComparator";
public static boolean isAscending() {
return isAscending;
}
public static void setAscending(boolean isAscending) {
DateComparator.isAscending = isAscending;
}
#Override
public int compare(MyList lhs, MyList rhs) {
String pattern = "MM/dd/yyyy";
try {
String dueDateLHS = lhs.getDueDate();//some field are null
String dueDateRHS = rhs.getDueDate();//some field are null
if(dueDateLHS!=null && dueDateRHS!=null){
SimpleDateFormat dateFormatLHS = new SimpleDateFormat(pattern);
SimpleDateFormat dateFormatRHS = new SimpleDateFormat(pattern);
Date dateLHS = dateFormatLHS.parse(dueDateLHS);
Date dateRHS = dateFormatRHS.parse(dueDateRHS);
if(isAscending)
return dateLHS.compareTo(dateRHS);
else
return dateRHS.compareTo(dateLHS);
}
} catch (ParseException e) {
Log.e(TAG, ""+e.getMessage());
e.printStackTrace();
}
return -1;
}
}
How should I resolve this issue?
You're not handling the case where one side is null and the other is not. You need to add something like:
else if(dueDateLHS == null && dueDateRHS!=null){
if(isAscending) {
return -1;
} else
return 1;
}
} else if (dueDateLHS != null && dueDateRHS==null){
//etc
} else if (dueDateLHS == null && dueDateRHS==null){
return 0;
}
I have code I am working on, but I am having issues populating the HashMap of HashMaps. The declaration goes as thus;
HashMap<Games, HashMap<Store, Integer>> myMap = new HashMap<Games, HashMap<Store, Integer>>();
Where Game and Store are separate object classes, with only a class variable title.
How do I create instances of the objects in the HashMaps and also populate the two hashmaps. Because I need to tag an Integer to the game in a particular store. Whereas there are different stores and different games in each store.
Thanks in Advance
Edit
Games Class
package gameStore;
public class Games {
private String title;
public Games(String inTitle){
setTitle(inTitle);
}
private String getTitle() {
return title;
}
private void setTitle(String title) {
this.title = title;
}
}
Stores Class
package gameStore;
public class LocalStores {
private String nameOfStore;
public LocalStores(String inNameOfStore){
setNameOfStore(inNameOfStore);
}
private void setNameOfStore(String nameOfStore){
this.nameOfStore = nameOfStore;
}
}
I would do something like this:
void addToMap(Games games, Store store, int value) {
HashMap<Store,Integer> m = myMap.get(games);
if (m == null) {
m = new HashMap<Store,Integer>();
myMap.put(games, m);
}
m.put(store, value);
}
UPDATE:
Since Games and Store are both used as keys to a HashMap, I would recommand that you add the hashCode and equals methods:
Games:
public int hashCode() {
return title.hashCode();
}
public boolean equals(Object obj) {
if (!(obj instanceof Games)) {
return false;
}
Games other = (Games)obj;
return title.equals(other.title);
}
LocalStores:
public int hashCode() {
return nameOfStore.hashCode();
}
public boolean equals(Object obj) {
if (!(obj instanceof LocalStores)) {
return false;
}
LocalStores other = (LocalStores)obj;
return nameOfStore.equals(other.nameOfStore);
}
Now, to keep it simple, let's say that each line of your input file contains three fields separated by tabs: the games' title, the store's name, and the integer value. You would read it as follows:
InputStream stream = new FileInputStream("myfile");
try {
Reader reader = new InputStreamReader(stream, "UTF-8"); // or another encoding
try {
BufferedInputStream in = new BufferedInputStream(reader);
try {
String line = in.readLine();
while (line != null) {
String[] fields = line.split("[\\t]");
if (fields.length == 3) {
addToMap(new Games(fields[0]), new LocalStores(fields[1]), Integer.parseInt(fields[2]));
}
line = in.readLine();
}
} finally {
in.close();
}
} finally {
reader.close();
}
} finally {
stream.close();
}