Related
//Represents list books command for biblioteca
public class ListBooksCommand implements Command {
private static final String BOOKS = "Books::";
private static final String FORMAT = "%-35s %-35s %-35s";
private static final String HEADER = String.format(FORMAT, "Name", "Author", "YearPublished");
private static final String NO_BOOKS_AVAILABLE = "No Books Available";
private final Biblioteca biblioteca;
private final IO io;
public ListBooksCommand(Biblioteca biblioteca, IO io) {
this.biblioteca = biblioteca;
this.io = io;
}
#Override
public void execute() {
if (this.biblioteca.isEmpty(Book.class)) {
this.io.println(NO_BOOKS_AVAILABLE);
return;
}
this.displayBooks();
}
private void displayBooks() {
this.io.println(BOOKS);
this.io.println(HEADER);
this.io.println(this.biblioteca.representationOfAllLibraryItems(Book.class));
}
}
public class ListMoviesCommand implements Command {
private static final String Movies = "Movies::";
private static final String FORMAT = "%-35s %-35s %-35s";
private static final String HEADER = String.format(FORMAT, "Name", "Director", "YearPublished");
private static final String NO_BOOKS_AVAILABLE = "No Movies Available";
private final Biblioteca biblioteca;
private final IO io;
public ListBooksCommand(Biblioteca biblioteca, IO io) {
this.biblioteca = biblioteca;
this.io = io;
}
#Override
public void execute() {
if (this.biblioteca.isEmpty(Movie.class)) {
this.io.println(NO_MOVIES_AVAILABLE);
return;
}
this.displayMovies();
}
private void displayMovies() {
this.io.println(MOVIES);
this.io.println(HEADER);
this.io.println(this.biblioteca.representationOfAllLibraryItems(MOVIE.class));
}
}
I have two classes here one is listbooks command , listmovies command both acts on biblioteca. Both Book and Movie is of type LibraryItem(interface).
Both below codes are same. Both will ask biblioteca to get the representation of its own type. And both commands will display the representation.
This is biblioteca implementation
//Represents a library
public class Biblioteca {
private final List<LibraryItem> allLibraryItems;
public String representationOfAllLibraryItems(Class<? extends LibraryItem> itemType) {
return this.allLibraryItems
.stream()
.filter(libraryItem -> libraryItem.getClass().equals(itemType))
.map(LibraryItem::representation)
.collect(Collectors.joining(LINE_SEPARATOR));
}
public boolean isEmpty(Class<? extends LibraryItem> itemType) {
return this.allLibraryItems.stream().noneMatch(libraryItem -> libraryItem.getClass().equals(itemType));
}
}
Please suggest me a pattern to avoid duplication.
Note: I'm not aware about your requirements. I'm just proposing some general design observations in this answer.
Observation 1: Biblioteca being a library, has library items. In your case, the items in the library are Movie items and Book items. So the library has two main types of items (or it can even contain more. Doesn't matter). Hence the member of Biblioteca should be:
private HashMap<Class<? extends LibraryItem>, List<LibraryItem>> libraryItems;
A map that has item type as Key and List<LibraryItem> as value.
Biblioteca should also contain querying methods that will return the representations for a given item type and representations for all item types. So in my view, Biblioteca class should look like this:
public class Biblioteca {
private HashMap<Class<? extends LibraryItem>, List<LibraryItem>> libraryItems;
public Biblioteca(HashMap<Class<? extends LibraryItem>, List<LibraryItem>> libraryItems) {
this.libraryItems = libraryItems;
}
/*
* Representation of a given type
*/
public String representationOfLibraryItemType(Class<? extends LibraryItem> itemType) {
if(libraryItems.containsKey(itemType)) {
return libraryItems.get(itemType).stream()
.filter(libraryItem -> libraryItem.getClass().equals(itemType))
.map(LibraryItem::representation)
.collect(Collectors.joining(System.lineSeparator()));
} else {
throw new IllegalArgumentException("Missing type " + itemType.getSimpleName());
}
}
/*
* Representation of all types
*/
public List<String> representationOfAllLibraryItems() {
return libraryItems.values()
.stream()
.flatMap(list -> list.stream()
.map(LibraryItem::representation))
.collect(Collectors.toList());
}
}
The method representationOfLibraryItemType should be taking in a Class of item type for filtering. If the item type is found in the library, return it's representations or else throw an exception saying it's an unknown item type.
On the other hand, representationOfAllLibraryItems() should not take any input parameters. It should return all the available representations in the library.
Observation 2: Your LibraryItem should be an abstract class and each of the items in your library should extend this particular class. Because Movie is-a LibraryItem and Book is-a LibraryItem. Now, each of your items can override representation() method which is an abstract method in LibraryItem. Your LibraryItem class should look something like this:
public abstract class LibraryItem {
abstract String representation();
}
Observation 3: Your Book and Movie classes should be independent of Biblioteca because they are just items in-a Library. Today they are in a library called Biblioteca and tomorrow they can be in a library called CentralHallLibrary. So, your item class should be looking something like this:
/*
* Book Item
*/
public class Book extends LibraryItem {
private String title;
private String author;
private String publishedYear;
public Book(String title, String author, String publishedYear) {
this.title = title;
this.author = author;
this.publishedYear = publishedYear;
}
#Override
public String representation() {
/*
* I'm just returning a call to toString
* from this method. You can replace it
* with your representation logic.
*/
return toString();
}
#Override
public String toString() {
return "Book [title=" + title + ", author=" + author + ", publishedYear=" + publishedYear + "]";
}
}
/*
* Movie Item
*/
public class Movie extends LibraryItem {
private String title;
private String director;
private String releaseYear;
public Movie(String title, String director, String releaseYear) {
this.title = title;
this.director = director;
this.releaseYear = releaseYear;
}
#Override
public String representation() {
/*
* I'm just returning a call to toString
* from this method. You can replace it
* with your representation logic.
*/
return toString();
}
#Override
public String toString() {
return "Movie [title=" + title + ", director=" + director + ", releaseYear=" + releaseYear + "]";
}
}
Observation 4: I didn't find any use of the Command class which you are using. Because, as I see, your Command class has only one method called execute() that is used for displaying the representations. Generally I would put such "displaying" code in my client side (UI). If Command class has no other functions other than only printing stuff, it's not necessary in my opinion.
Testing the design: Let's create few Book items and few Movie items and then add those to the Biblioteca library
Book effJava = new Book("Effective Java", "Josh Bloch", "2008");
Book cloudNativeJava = new Book("Cloud Native Java", "Josh Long", "2017");
Book java9modularity = new Book("Java 9 Modularity", "Paul Bakker", "2017");
Movie gotgV2 = new Movie("Guardians of the Galaxy Vol. 2", "James Gunn", "2017");
Movie wonderWoman = new Movie("Wonder Woman", "Patty Jenkins", "2017");
Movie spiderHomeCmg = new Movie("Spider-man Homecoming", "Jon Watts", "2017");
List<LibraryItem> bookItems = new ArrayList<>();
List<LibraryItem> movieItems = new ArrayList<>();
bookItems.add(java9modularity);
movieItems.add(spiderHomeCmg);
bookItems.add(cloudNativeJava);
movieItems.add(wonderWoman);
bookItems.add(effJava);
movieItems.add(gotgV2);
HashMap<Class<? extends LibraryItem>, List<LibraryItem>> store = new HashMap<>();
store.put(Movie.class, movieItems);
store.put(Book.class, bookItems);
//CREATE STORE
Biblioteca bibloiteca = new Biblioteca(store);
Now, on querying the library for all representations -
List<String> allLibraryItemsRep = bibloiteca.representationOfAllLibraryItems();
Will return a result having both Movie and Book representations.
On querying the library for specific item types -
String movieRep = bibloiteca.representationOfLibraryItemType(Movie.class);
String bookRep = bibloiteca.representationOfLibraryItemType(Book.class);
Will return specific representations -
Movie [title=Spider-man Homecoming, director=Jon Watts, releaseYear=2017]
Movie [title=Wonder Woman, director=Patty Jenkins, releaseYear=2017]
Movie [title=Guardians of the Galaxy Vol. 2, director=James Gunn, releaseYear=2017]
Book [title=Java 9 Modularity, author=Paul Bakker, publishedYear=2017]
Book [title=Cloud Native Java, author=Josh Long, publishedYear=2017]
Book [title=Effective Java, author=Josh Bloch, publishedYear=2008]
On querying the library for the type which is not present in the library -
String carRep = bibloiteca.representationOfLibraryItemType(Car.class);
Will throw an exception -
java.lang.IllegalArgumentException: Missing type Car
I understand that this is quite a lengthy answer and hope this brought some clarity about the design.
You can create a generic class ListItemsCommand which will accept the item name or class as a parameter for listing and checking for empty list.
And then call ListItemsCommand with the item type like Movie or Book
If you want to remove duplication I suggest using a collect with groupingBy. This allows you to specify which is the key used for deduplication (or grouping) and a reduction function which in case of a duplicate selects the element which is to be selected from the set of duplicates.
Here is a sample method with the groupingBy collector:
public String representationOfAllLibraryItems(Class<? extends LibraryItem> itemType) {
return this.allLibraryItems
.stream()
.filter(libraryItem -> libraryItem.getClass().equals(itemType))
.collect(Collectors.groupingBy(LibraryItem::getName, LinkedHashMap::new,
Collectors.reducing((o1, o2) -> o1.toString().compareTo(o2.toString()) < 0 ? o1 : o2)))
.values()
.stream()
.map(Optional::get)
.map(LibraryItem::representation)
.collect(Collectors.joining(LINE_SEPARATOR));
}
Here is a small test in which we de-duplicate by name of the movie and select the most recent entry in the data:
public static void main(String[] args) {
List<LibraryItem> items = Arrays.asList(new Movie("Valerian", "Luc Besson", "2017"),
new Movie("Valerian", "Luc Besson", "2016"),
new Movie("Spiderman", "Sam Raimi", "2002"),
new Movie("Spiderman", "Sam Raimi", "2001"),
new Movie("Spiderman", "Sam Raimi", "2003"));
Biblioteca biblioteca = new Biblioteca(items);
System.out.println(biblioteca.representationOfAllLibraryItems(Movie.class));
}
The result looks like this:
Luc Besson - Valerian - 2017
Sam Raimi - Spiderman - 2003
Here the de-duplication happens by movie name and the most recent movie is selected.
I am trying to retrieve certain values from multiple objects under the same class. I have used a for each loop to iterate through each object, and would like to create an aggregated total, representing the rating and the cost of the item from the objects.
The For Each loop in my parent class:
for (Song songObj : Song.returnSongs()) {
totalSongCost += Double.parseDouble(songObj.getPrice());
totalSongRating += Integer.parseInt(songObj.getRating());
}
The Child class ArrayList meant to store objects:
private int rating;
private String title;
private double price;
private boolean favorite;
private static int counter = 0;
private static ArrayList songArray = new ArrayList();
/**
* Constructor for objects of class Song
*/
public Song()
{
// initialise instance variables
rating = 0;
title = "";
price = 0.0;
counter++;
songArray.add(this);
}
public static ArrayList returnSongs() {
return songArray;
}
When I compile the code I get an error message saying that an object cannot be converted to song. Is there a way to fix this, or an easier way to accomplish the same task?
If you've ever read the docs, you will know that ArrayList is actually a generic class. That means you can give ArrayList a type.
The type of stuff that an array list can store depends on what type you gave it. But if you don't give it any type, it stores Objects! Here,
for (Song songObj : Song.returnSongs()) {
you want to get Song objects from an array list of Object objects, which makes no sense to the compiler. As a result, the error appears.
The solution to this problem is of course, give the array list a type so that it knows what type it should store.
Change this
private static ArrayList songArray = new ArrayList();
to this:
private static ArrayList<Song> songArray = new ArrayList<>();
and change this:
public static ArrayList returnSongs() {
to this:
public static ArrayList<Song> returnSongs() {
ArrayList is a generic class. This means you can specify what class type it is meant to work with. if you change this:
private static ArrayList songArray = new ArrayList();
to this:
private static ArrayList<Song> songArray = new ArrayList<Song>();
Then the ArrayList class will understand that you're working with instances of Song.
Edit: as Jim Garrison pointed out, your returnSongs() method should also be changed to specify the class type in the same way.
public static ArrayList<Song> returnSongs() { ...
It's a little unusual to have the Song class be responsible for keeping track of all of the songs within the application. That seems outside of the responsibility of that class, and perhaps better suited to be handled within a different class, either within your parent class or a new type specially defined.
Additionally, be careful when using types like List and ArrayList. As your compiler will warn you, these require type parameters in angle brackets (i.e. List<Type>). You should make it a habit of addressing all compiler warnings, and of always specifying type parameters for generic types like List. In cases where you don't define your types correctly, things start to default to Object, which leads to the issue you faced here.
Below is an example of what this could look like, restructured to keep the Song class solely for attributes of the song itself:
import java.util.ArrayList;
import java.util.List;
public class Parent {
private static List<Song> songs = new ArrayList<Song>();
private static double totalSongCost = 0.0;
private static int totalSongRating = 0;
public static void main(String[] args) {
populateSongs();
for (Song song : songs) {
totalSongCost += songObj.getPrice();
totalSongRating += songObj.getRating();
}
}
private void populateSongs() {
songs.add(new Song(5, "Hey Jude", 12.5));
songs.add(new Song(4, "Angie", 11.5));
songs.add(new Song(0, "Other", 10.5));
}
}
Your song class would simply be this:
public class Song {
private int rating = 0;
private String title = "";
private double price = 0.0;
public Song(int rating, String title, double price) {
this.rating = rating;
this.title = title;
this.price = price;
}
// Compressed for brevity
public int getRating() { return rating; }
public String getTitle() { return title; }
public double getPrice() { return price; }
}
I came across a problem while practising Java.
I have a class Book which stores the following information:
id (int), author and title
and I have another class BookShelf which store a collection of books using a Vector/ArrayList and have the following methods:
addBook: takes in a book object as input, adds the object into the bookshelf, method returns nothing.
returnListOfBooks: takes in no argument and returns a Vector/ArrayList of all books sorting by title in alphabetical order.
returnListOfBooksByAuthor: takes in author as input and returns a Vector/ArrayList of books by that author
My question is, how do I create the method returnListOfBooks and sort them by title in alphabetical order? It would also be great if you could check my methods and correct me if what i'm doing is wrong.
I have to implement the sorting (bubble sort, insertion sort, and such)
I'm new to java so i'm not quite good at it. Any help would be greatly appreciated!
In Java you typically sort a List with Collections.sort and if needed a custom comparator. Java 8 allows a concise syntax for that.
// easy to change for descending order
Collections.sort(listOfBooks, (a, b) -> a.getTitle().compareTo(b.getTitle()));
or even better
Collections.sort(listOfBooks, Comparator.comparing(Book::getTitle));
Mind you that both will sort listOfBooks in place (instead of returning a new sorted list). You probably don't want to do that every time you call returnListOfBooks. If for e.g. inside returnListOfBooksByAuthor you do
Collections.sort(listOfBooks, Comparator.comparing(Book::getAuthor));
The same listOfBooks will be sorted in place according to author this time
You would need to make your Book class implement the Comparable interface, and then, compare the names of the books.
Now, the Java Framework already provides a sorting mechanism to sort lists through Collections.sort. If you implement the interface above, you should be able to simply call Collections.sort(listOfBooks) and have your collection sorted.
Alternatively, if you need to implement your own sorting mechanism, you can simply do so and then compare the books by using the .compareTo method which the Comparable interface gives you.
While you do need to make your Book objects Comparable to one another, another error you'd likely see with your current code is a concurrent modification exception because you are sorting a list while iterating over it.
So your method should look like this since the requirements are to return a sorted list, not print it.
Note, if you want to keep the initial ordering of listOfBooks before and after calling this method, you'll need to copy the whole list out to another list which you sort and return instead.
public ArrayList<Book> returnListOfBooks()
{
Collections.sort(listOfBooks);
// could print them, also, if you wish
return listOfBooks;
}
Book Class
import java.util.Comparator;
import java.util.Objects;
public class Book implements Comparable {
private String bookName;
private String autherName;
private String isbn;
public Book(String bookName, String autherName, String isbn) {
this.bookName = bookName;
this.autherName = autherName;
this.isbn = isbn;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAutherName() {
return autherName;
}
public void setAutherName(String autherName) {
this.autherName = autherName;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
#Override
public int compareTo(Book book) {
return this.bookName.compareTo(book.bookName);
}
#Override
public int hashCode() {
int hash = 7;
hash = 53 * hash + Objects.hashCode(this.bookName);
return hash;
}
#Override
public String toString(){
return bookName +" "+autherName + " "+isbn;
}}
Book Shelf
public class BookShelf {
private ArrayList<Book> bookList = new ArrayList<Book>();
public void addBook(Book book) {
bookList.add(book);
}
public ArrayList<Book> bookList(String sortBy) {
ArrayList<Book> list = new ArrayList<Book>(bookList);
SortingComparator comparator = null;
if (sortBy.equals("auther")) {
comparator = new AutherComparator();
} else if (sortBy.equals("bookname")) {
comparator = new BookNameComparator();
}
Collections.sort(list, comparator);
return list;
}}
Comparators
interface SortingComparator extends Comparator<Book> {}
class AutherComparator implements SortingComparator {
#Override
public int compare(Book b1, Book b2) {
return (b1.getAutherName().toUpperCase()).compareTo((b2.getAutherName().toUpperCase()));
}
}
class BookNameComparator implements Comparator<Book>,SortingComparator {
#Override
public int compare(Book b1, Book b2) {
return (b1.getBookName().toUpperCase()).compareTo((b2.getBookName().toUpperCase()));
}}
Main CLass
public static void main(String s[]) {
BookShelf bookShelf = new BookShelf();
bookShelf.addBook(new Book("Algorithm", "Toman", "12-34"));
bookShelf.addBook(new Book("DataBase", "Sethi", "12-35"));
bookShelf.addBook(new Book("DataStruture", "Ulman", "12-36"));
bookShelf.addBook(new Book("Network", "Tanenbom", "12-37"));
ArrayList<Book> list = bookShelf.bookList("auther");
System.out.println("----Sort by Auther-----------");
for (Book b : list) {
System.out.println(b);
}
System.out.println("----Sort by Book Name-----------");
list = bookShelf.bookList("bookname");
for (Book b : list) {
System.out.println(b);
}
}
After developing in PHP for a long time I have decided to step into Java. Comfortable in OOP methodology and all that, I'm trying to start off at that point within java, but I'm getting hung up on passing out my arraylist object into a for statement to be printed back out using the Item class methods.
HelloInvetory.java
package helloInventory;
import java.util.Arrays;
public class HelloInventory {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Object InvetoryItems;
Inventory inv = new Inventory();
inv.createItemObj(101, "camera", "Used camera that I bought off of a homeless guy.", 500);
InvetoryItems = inv.getAllInventoryItems();
for(Object item : InvetoryItems){
System.out.println(item.getItemName());
}
System.out.println("Done");
}
}
Inventory.java
package helloInventory;
import java.util.*;
/**
* Tracks and maintains all items within the inventory
* #author levi
*
*/
public class Inventory {
List<Object> InventoryItems = new ArrayList<Object>();
/*
* create object from Items class
* and insert into Object[] array.
*/
public void createItemObj(int sku, String name, String descriptor, float price) {
Items item = new Items();
item.setSku(sku);
item.setItemName(name);
item.setItemDescription(descriptor);
item.setItemPrice(price);
this.setInventoryItems(item);
}
public Object getAllInventoryItems() {
//return InventoryItems;
return this.InventoryItems.toArray();
}
public void setInventoryItems(Object inventoryItems) {
//InventoryItems.add(inventoryItems);
this.InventoryItems.add(inventoryItems);
}
}
Items.java
package helloInventory;
/**
* Class object to hold each item details
* #author levi
*
*/
public class Items {
int sku;
String itemName;
String itemDescription;
float itemPrice;
public int getSku() {
return sku;
}
public void setSku(int sku) {
this.sku = sku;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getItemDescription() {
return itemDescription;
}
public void setItemDescription(String itemDescription) {
this.itemDescription = itemDescription;
}
public float getItemPrice() {
return itemPrice;
}
public void setItemPrice(float itemPrice) {
this.itemPrice = itemPrice;
}
}
Where I am stuck is within the HelloInventory.java
for(Object item : InvetoryItems){
System.out.println(item.getItemName());
}
IDE (Eclipse) gives me the error "Can only iterate over an array or an instance of java.lang.Iterable". Is there something extra I need, or I'm I going around this totally the wrong way in Java? Correct example would be helpful.
Best,
Levi
You have a very strange architecture here my friend. You shouldn't be using generic Objects everywhere, but the actual types. First thing:
public Object getAllInventoryItems() {
//return InventoryItems;
return this.InventoryItems.toArray();
}
Why not just return the List itself?
public List<Item> getAllInventoryItems() {
return this.InventoryItems;
}
Also change this:
List<Item> InventoryItems = new ArrayList<Item>();
and this:
public void setInventoryItems(Item inventoryItems) {
this.InventoryItems.add(inventoryItems);
}
Now iterating the List is smooth sailing:
public static void main(String[] args) {
// TODO Auto-generated method stub
List<Item> InvetoryItems;
Inventory inv = new Inventory();
inv.createItemObj(101, "camera", "Used camera that I bought off of a homeless guy.", 500);
InvetoryItems = inv.getAllInventoryItems();
for(Item item : InvetoryItems){
System.out.println(item.getItemName());
}
System.out.println("Done");
}
Btw, I changed Items to Item out of habit. A class name should indicate a single entity so by convention it's singular.
Now don't take this the wrong way, but you may have got off on the wrong foot with Java, so I highly recommend this reading: http://www.mindview.net/Books/TIJ/ This worked for me when I was starting with Java, maybe others can suggest some good sources as well.
Ok, two things. One is that Tudor is absolutely right, it's best to use the classes you're expecting directly, not Objects, and stylistically his points are accurate too.
Two is that if you really have to use a list of object, you'll need to cast back from object to whatever type it is that you're expecting to receive.
List<Object> list = inv.getAllInventoryItems();
for (Object item : list){
System.out.println((Items) item).getItemName();
}
However, I wouldn't recommend doing this as it effectively takes what should be a compile-time error and makes it a RunTime error (if the class cannot be cast).
I am trying to make a project that adds cd / dvd /movie info from main() to a collections library
then prints info added.
like: output
-Book-
author: Robert A. Heinlein
# pages: 325
title: Starship Troopers
keywords: science fiction, war, weapons
-Music-
band: five finger death punch
# songs: 15
members: Zoltan Bathory, Ivan Moody,Jeremy Spencer,Matt Snell,Jason Hook
title: War is the answer
keywords: rock
I currently have 6 classes
1.project1 - main()
2.Library - where im adding to database
3.item - inheritance(title & number)
4.cd
5.dvd
6.movie
i am trying to use inheritance so i want to keep the files i have.
My question is i am trying to add to the collections in the library class. I am just not sure how to do it.
here is the classes i think you will need to see..
import java.io.PrintStream;
import java.util.Collection;
public class project
{
private static Library library = new Library();
public static void main(String[] args)
{
PrintStream out = System.out; // we will be printing to the standard output stream
Item item;
// add items to library
out.println(">>> adding items to library:\n");
item = library.addBook("The Curious Incident of the Dog in the Night-Time", "Mark Haddon", 240, "autism", "Asperger's Syndrome");
if (item != null)
library.printItem(out, item);
item = library.addBook("Starship Troopers", "Robert A. Heinlein", 325, "science fiction", "war", "weapons");
if (item != null)
library.printItem(out, item);
item = library.addBook("The Moon Is A Harsh Mistress", "Robert A. Heinlein", 389, "science fiction", "moon", "social structures");
if (item != null)
library.printItem(out, item);
item = library.addMusicCD("Europe In '72", "Grateful Dead", 12, "acid rock", "sixties", "jam bands");
if (item != null) {
library.addBandMembers(item, "Jerry Garcia", "Bill Kreutzman", "Keith Godcheaux");
library.printItem(out, item);
}
item = library.addMusicCD("Don't Let Go", "Jerry Garcia Band", 15, "acid rock", "jam bands");
if (item != null) {
library.addBandMembers(item, "Jerry Garcia", "Keith Godcheaux");
library.printItem(out, item);
}
item = library.addMusicCD("Sergeant Pepper's Lonely Hearts Club Band", "Beatles", 10, "acid rock", "sixties");
if (item != null) {
library.addBandMembers(item, "John Lennon", "George Harrison", "Ringo Starr");
library.printItem(out, item);
}
item = library.addMovieDVD("Lost In Translation", "Sofia Coppola", 14, "Japan", "loneliness");
if (item != null) {
library.addCast(item, "Bill Murray", "Scarlett Johansson");
library.printItem(out, item);
}
item = library.addMovieDVD("Groundhog Day", "Harold Ramis", 14, "newscaster", "groundhog", "time");
if (item != null) {
library.addCast(item, "Bill Murray", "Andie MacDowell");
library.printItem(out, item);
}
// print books, musicCDs, movies
out.println(">>> books:\n");
printItems(out, library.books());
out.println(">>> music CDs:\n");
printItems(out, library.musicCDs());
out.println(">>> movies:\n");
printItems(out, library.movies());
// print items for keyword
printItemsForKeyword(out, "science fiction");
printItemsForKeyword(out, "jam bands");
printItemsForKeyword(out, "xxx");
// items by artist
out.println(">>> books by Robert A. Heinlein:\n");
printItems(out, library.booksByAuthor("Robert A. Heinlein"));
out.println(">>> music by the Grateful Dead:\n");
printItems(out, library.musicByBand("Grateful Dead"));
out.println(">>> music by the Rolling Stones:\n");
printItems(out, library.musicByBand("Rolling Stones"));
out.println(">>> movies by Sofia Coppola:\n");
printItems(out, library.moviesByDirector("Sofia Coppola"));
out.println(">>> music by Jerry Garcia:\n");
printItems(out, library.musicByMusician("Jerry Garcia"));
out.println(">>> movies with Bill Murray:\n");
printItems(out, library.moviesByActor("Bill Murray"));
}
private static void printItemsForKeyword (PrintStream out, String keyword)
{
Collection<Item> items;
out.printf(">>> items for keyword: %s\n\n", keyword);
items = library.itemsForKeyword(keyword);
printItems(out, items);
}
private static void printItems (PrintStream out, Collection<Item> items)
{
if (items != null && items.size() > 0)
for (Item item : items)
library.printItem(out, item);
else
out.println("none\n");
}
}
here is the library class where i am having trouble adding to the collections..
How would i add a book or a cd to the collections?
import java.io.PrintStream;
import java.util.Collection;
import java.util.*;
public class Library
{
// returns all of the items which have the specified keyword
public Collection<Item> itemsForKeyword(String keyword)
{
return null;
}
// print an item from this library to the output stream provided
public void printItem(PrintStream out, Item item)
{
}
// adds a book to the library
public Item addBook(String title, String author, int nPages, String... keywords)
{
return null;
}
// returns all of the books by the specified author
public Collection<Item> booksByAuthor(String author)
{
return null;
}
// returns all of the books in the library
public Collection<Item> books()
{
return null;
}
// music-related methods
// adds a music CD to the library
public Item addMusicCD(String title, String band, int nSongs, String... keywords)
{
Collection MusicCollection = new HashSet();
MusicCollection.add(title);
return null;
}
// adds the specified band members to a music CD
public void addBandMembers(Item musicCD, String... members)
{
}
// returns all of the music CDs by the specified band
public Collection<Item> musicByBand(String band)
{
return null;
}
// returns all of the music CDs by the specified musician
public Collection<Item> musicByMusician(String musician)
{
return null;
}
// returns all of the music CDs in the library
public Collection<Item> musicCDs()
{
return null;
}
// movie-related methods
// adds a movie to the library
public Item addMovieDVD(String title, String director, int nScenes, String... keywords)
{
return null;
}
// adds the specified actors to a movie
public void addCast(Item movie, String... members)
{
}
// returns all of the movies by the specified director
public Collection<Item> moviesByDirector(String director)
{
return null;
}
// returns all of the movies by the specified actor
public Collection<Item> moviesByActor(String actor)
{
return null;
}
// returns all of the movies in the library
public Collection<Item> movies()
{
return null;
}
}
here is the items class
import java.io.PrintStream;
import java.util.Collection;
import java.util.*;
public class Item
{
private String title;
private int number;
public Item(String theTitle, int theNumber)
{
number = theNumber;
title = theTitle;
}
public String getTitle()
{
return title;
}
public int getNumber()
{
return number;
}
}
here is the cd class - the dvd class is almost identical
import java.util.*;
public class CD extends Item
{
private String artist;
private String members;
public CD(String theTitle, String theArtist, String theMembers, int number)
{
super(theTitle,number);
artist = theArtist;
members = theMembers;
}
public String getArtist()
{
return artist;
}
public String getMembers()
{
return members;
}
public void print()
{
System.out.println("-Music-");
System.out.println("band: " + artist);
}
}
I am not sure if i could combine the cd/dvd/movie classes into items class?
My main QUESTION is:
how should i add each cd/dvd to collections?????
in the library class
would i just define a collection to add in every addfunction(addMusicCD,addBandMembers,addMovieDVD,etc..) or should i put the collection in the beginning of the class? and how do i add to that collection???
public Item addMusicCD(String title, String band, int nSongs, String... keywords)
{
Collection MusicCollection = new HashSet(); // how should i add each cd/dvd to collections?????
MusicCollection.add(title);
return null;
}
I am also trying to return an Item and cannot! what item would i need to return??
I know this is alot of information. Sorry.
Hopefully someone can help me and not just make fun of me. i am trying to learn java from c++
Thank you for any help you can give me..
I think you need to study Object Orientation Principles a bit more.
The Library should be able to add Items. The Library methods addBook(many params) and addDVD() etc should be replaced by a more generic addItem(Item item, String... keywords).
Items can be CDs, DVDs or Movies. It's up the the CD class to add band members, not the Library class.
Adding an item to the library becomes something like
CD cd = new CD("Europe In '72", "Grateful Dead", 12);
cd.addBandMembers("Jerry Garcia", "Bill Kreutzman", "Keith Godcheaux");
library.addItem(cd, "acid rock", "sixties", "jam bands"));
Hope this helps a little to get you on track.
In addMusicCD, do a new CD(the various bits).
Add the resulting CD to the collection.
Return it.
It might be easier for you to fit this all together if you used Generics to declare collections, e.g.
class Library {
private Set<CD> theCDs;
public Item addCD(String title) {
CD cd = new CD(title);
theCDS.add(cd);
return cd;
}
}
etc, etc. etc.
I would probably add another tree of inheritance, so a Library is an abstract subclass of e.g. HashSet:
public abstract class Library<T extends Item> extends HashSet<T>{
...
abstract void addItem(T item);
}
Then you create all your libraries by subclassing your Library-class:
public class CDLibrary extends Library<Cd>{
...
#Override
public void addItem(Cd item){
// Maybe add some information of cd to a hashmap for lookups, or whatever
...
this.add(item);
}
When you're subclassing HashSet, all the add and delete operations are done for you.
If you dont need specific add-methods for each Item, you can simply remove the abstract mathod of Library, and just take advantage of the generic-syntax, to specify a new type of library when subclassing.
You might consider subclassing ArrayList, or something similar instead, as HashSet does not have a get() method, which ArrayList does, the above code was just an example of what you could do.
If its unclear, I'll try to clarify a bit more! But I hope you get the picture - subclassing to inherit the functions you need, instead of creating them again. Generics, (do you know generics?) are to ensure type-safety, so you cannot add a DVD to a CDLibrary.
Also, be sure to override equals() and hashcode() of your Items, to make sure you can distinguish between two Items.
I hope it makes sense!
Do you need to have the CDs, DVDs, and Books into separate data structures? What's your use case? If you need to get them in a separate way, then having different data structures is OK.
Otherwise, and I think this is the case, I think you could be fine having a Set<Item> and dump all your items in it.
public static class Library{
private Set<Item> items = new HashSet<Item>();
public void add(Item i){
items.add(i);
}
public String toString(){
return items.toString()
}
}
And, in your Item sub-classes, you have to have toString() overridden, and everything will print itself just fine.