Method to check a Object's variables within an ArrayList - java

I'm having issues creating the following two methods using an ArrayList object:
existTextbook(): checks whether a given textbook is in the catalogue. existTextbook() accepts the title and the author and returns true or false. True if the textbook is in the catalogue, false otherwise.
deleteTexbook(): deletes a textbook from the catalogue. deleteTextbook() accepts a textbook title as parameter and deletes the textbook if it exists.
Searching the Java API, the closest method I can find for the first method is the contains method but it takes an object as a parameter, not a String object within the Textbook object like the title or author. The same is true for the remove method for the second method taking an object of the ArrayList as a parameter.
Any hints on how to have a method look at each Textbook object String title or author, then return true if a match is found, or to delete the Textbook object containing the Textbook object String title or author?
Here's my code so far:
Textbook Class
package Ex1;
import java.text.NumberFormat;
public class Textbook
{
private String category, title, author;
private int year;
private double price;
public Textbook (String category, String title, String author, int year,
double price)
{
this.category = category;
this.title = title;
this.author = author;
this.year = year;
this.price = price;
}
public String toString()
{
NumberFormat fmt = NumberFormat.getCurrencyInstance();
String description;
description = "Category: " + category + "\n";
description += "Title: " + title + "\n";
description += "Author: " + author + "\n";
description += "Year: " + year + "\n";
description += "Price: " + fmt.format(price) + "\n" + "\n";
return description;
}
}
Catalogue Class
package Ex1;
import java.util.ArrayList;
public class Catalogue
{
private ArrayList <Textbook> catalogue;
public Catalogue ()
{
catalogue = new ArrayList<Textbook>();
}
public void addTextbook (Textbook t)
{
catalogue.add(t);
}
public boolean existTextbook(String title, String author)
{
}
public void deleteTextbook(String title)
{
}
public String toString()
{
return catalogue.toString();
}
}
Driver Class
package Ex1;
public class Drivermain
{
public static void main(String[] args)
{
Textbook javaBook = new Textbook ("Computer Science",
"Java Software Solutions", "Lewis/Loftus", 2015, 163.45);
Textbook dataBook = new Textbook ("Computer Science",
"Data Structures and Algorithm Analysis in Java,",
"Mark A. Weiss", 2015, 181.90);
Textbook calcBook = new Textbook ("Mathematics",
"Calculus Plus NEW MyMathLab", "Briggs/Cochran/Gillett",
2015, 236.90);
Textbook osBook = new Textbook ("Computer Science",
"Operating Systems: Internals and Design Principles",
"William Stallings", 2015, 205.70);
Textbook historyBook = new Textbook ("History",
"History of the Canadian Peoples: Beginnings to 1867, Vol. 1",
"Conard/Finkel/Fyson", 2015, 96.90);
Catalogue bookCatalogue = new Catalogue();
bookCatalogue.addTextbook(javaBook);
bookCatalogue.addTextbook(dataBook);
bookCatalogue.addTextbook(calcBook);
bookCatalogue.addTextbook(osBook);
bookCatalogue.addTextbook(historyBook);
System.out.println(bookCatalogue);
bookCatalogue.existTextbook("Java Software Solutions", "Lewis/Loftus");
bookCatalogue.deleteTextbook("Java Software Solutions");
}
}

I think instead of using methods from collections, you may want to deal with looking in your Arraylist yourself.
I'm not using a for each loop (just a for loop) because for delete it will cause a concurrent modification exception.
package Ex1;
import java.util.ArrayList;
public class Catalogue
{
private ArrayList <Textbook> catalogue;
public Catalogue ()
{
catalogue = new ArrayList<Textbook>();
}
public void addTextbook (Textbook t)
{
catalogue.add(t);
}
public boolean existTextbook(String title, String author)
{
for(int i =0; i<catalogue.Size(); i++){
Textbook t = catalogue.get(i);
//you'll want getter and setter methods
if(t.author.equals(author)&&t.title.equals(title))
return truel
}
}
public void deleteTextbook(String title)
{
for(int i =0; i<catalogue.Size(); i++){
Textbook t = catalogue.get(i);
if(t.title.equals(title)){
catalogue.remove(i);
}
}
}
public String toString()
{
return catalogue.toString();
}
}
Happy Coding! Leave a comment if you have any questions.

Instead of directly using those methods you may consider just looping through the catalogue ArrayList yourself and testing if the current object matches the title (and author).
It might be overkill, but you could make Textbook implement Comparable or write a Comparator.

Related

How do i use this copyOf array function in my java code?

Im trying to create a new instance in my book array, i've researched on the copyof method and thats supposedly how you do it, however, when I run the code that supposedly does it, i dont get any error or anything but it just doesnt show up? the output shows the other 3 books but not the added harry potter one.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Book book1 = new Book("The Alchemist", "Paulo Coelho", "HarperCollins", "Adventure");
Book book2 = new Book("The Great Gatsby", "F. Scott Fitzgerald", "Charles Scribner\'s Sons", "Fiction");
Book book3 = new Book("The Catcher in the Rye", "J. D. Salinger", "Little, Brown and Company", "Fiction");
// Create an instance of the class Author
Author author1 = new Author("Paulo", "Coelho");
Author author2 = new Author("F. Scott", "Fitzgerald");
Author author3 = new Author("J. D.", "Salinger");
// Create an instance of the class Publisher
Publisher publisher1 = new Publisher("HarperCollins");
Publisher publisher2 = new Publisher("Charles Scribner\'s Sons");
Publisher publisher3 = new Publisher("Little, Brown and Company");
String[] authors = {author1.toString(), author2.toString(), author3.toString()};
String[] publishers = {publisher1.toString(), publisher2.toString(), publisher3.toString()};
String[] books = {book1.toString(), book2.toString(), book3.toString()};
addBook(authors, publishers, books, "J. K. Rowling", "Bloomsbury", "Harry Potter and the Philosopher\'s Stone", "trash");
//System.out.println(Arrays.toString(books));
//displayBooks(books);
// displayAuthors(authors);
//displayPublishers(publishers);
}
public static void addBook(String[] authors, String[] publishers, String[] books, String author, String publisher, String book, String genre){
authors = Arrays.copyOf(authors, authors.length + 1);
authors[authors.length - 1] = author;
publishers = Arrays.copyOf(publishers, publishers.length + 1);
publishers[publishers.length - 1] = publisher;
books = Arrays.copyOf(books, books.length + 1);
books[books.length - 1] = book;
}
public static void displayAuthors(String[] authors){
for(String author : authors){
System.out.println(author);
}
}
public static void displayPublishers(String[] publishers){
for(String publisher : publishers){
System.out.println(publisher);
}
}
public static void displayBooks(String[] books) {
for (String book : books) {
System.out.println(book);
}
}
}
Constructor for book:
public class Book {
String title;
String author;
String publisher;
String genre;
public Book(String title,String author,String publisher,String genre) {
this.title = title;
this.author = author;
this.publisher = publisher;
this.genre = genre;
}
public String toString() {
return this.title + " | " + this.author + " | " + this.publisher + " | " + this.genre;
}
}
I've tried
System.out.println(Arrays.toString(books));
There is no error, so maybe it does happen but when i go to print the array itself it doesnt show up
(I'd like all 4 books to show instead of the original 3)
In your addBook method:
authors = Arrays.copyOf(authors, authors.length + 1);
authors[authors.length - 1] = author;
authors is your own local variable. You create a new array here (with copyOf), and assign it to this local copy. You then change something in this array you just made, and then your method ends. With it, your local variable poofs out of existence, and with that, no code has any reference to this copied array. The garbage collector eventually removes it.
The entire method therefore does nothing.
Generally, don't have static anything when you start out (other than your main, which should contain just one line: new MyClass().go(), or possibly new MyClass().go(args) if you care about the args; no further use of static allowed until you're a bit further along in your java career.
If you want things to survive, they have to be fields.

I'm trying to read this text file

I made a two classes, one text file, and a code that should print everything out, but it still becomes null no matter what I do? I'm trying to read the code from the text file by using the toString method from the Book class and the printInventory from the Inventory class in the InventoryTester.
My first code derives on what should be printed. I made a constructor and I used setters and getters to make this. Then ended it with a toString() method. I made a Book class that should print everything to the printInventory in the InventoryTester.
Book class:
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.lang.*;
public class Book {
// Initiate variables
// Note: I used the DecimalFormat so every price is always going to have 2 decimal spaces
private static DecimalFormat df2 = new DecimalFormat("#.##");
private String ISBN;
private String author;
private String title;
private int edition;
private String pubCode;
private int quantity;
private double price;
//constructor
public Book(String isbn, String auth, String ti, int ed, String pc, int qty, double pr)
{
ISBN = isbn;
author = auth;
title = ti;
edition = ed;
pubCode = pc;
quantity = qty;
price = pr;
}
//getters
public String getTitle(){return title;}
public String getAuthor(){return author;}
public double getPrice(){return price;}
public int getEdition(){return edition;}
public String getISBN(){return ISBN;}
public String getpubCode(){return pubCode;}
public int getQuantity(){return quantity;}
//setters
public void changePrice(double newPrice){price = newPrice;}
public boolean changeQuantity(int changeAmt){
changeAmt = quantity + changeAmt;
if (changeAmt < 0) {
return false;
}
else {
return true;
}
}
//This prints out all of the information once the object 'Book' is used
public String toString()
{
String subAuthor = "";
String subTitle = "";
subAuthor = author.substring(0,16);
subTitle = title.substring(0,32);
return "ISBN: " +ISBN + "\nAuthor: " + subAuthor + "\nTitle: " + subTitle + "\nEdition: " + edition + "\nPublisher Code: " + pubCode +"\nQuantity: " +quantity+ "\nPrice: $ " +df2.format(price) + "\n\n";
}
}
Then I made a class called Inventory to manage instances of the Book class. However, I'm still not sure if most of my code is correct since I compiled it without any errors. What I mean is the constructor itself, the addBook method and the changeQuantity method.
The constructor takes one argument, which is the size of the books array. It should create the empty array of the specified size, and initializes the nextEntry field to be 0. I use the printInventory method here. This method should print the entire inventory from the Book class, using the toString()method on each book.
Inventory class:
import java.math.RoundingMode;
import java.text.DecimalFormat;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import java.util.Arrays;
public class Inventory {
private Book[] books;
private int nextEntry;
int questionAmt;
public Inventory(int size){
size = 7;
books = new Book[size];
nextEntry = 0;
}
public boolean addBook(Book theBook) {
if (nextEntry > 27)
{ return false;}
else{
nextEntry++;
books[nextEntry] = theBook;
return true;
}
}
public boolean changeQuantity(String isbn, int changeAmt) {
if (changeAmt < 0) {
return false;
}
else {
return true;
}
}
public void printInventory()
{
for (int i=0; i<books.length; i++) {
System.out.println(books[i].toString());
return;
}
}
Then I added the text file, which is called inventory. This is what should be shown in the code and I should be able to edit the quantity it inside the console. I also added a 28 because it needs 28 Books.
inventory.txt:
28
013478796X_Tony Gaddis_Starting Out with Java: From Control Structures through Data Structures_4_PE_10_121.75
0321409493_John Lewis_Java Software Solutions: Foundations of Program Design_5_AW_12_94.05
0023606924_Richard Johnsonbaugh_Algorithms_1_PH_1_109.00
0134743350_Harvey Dietel_Java: How to Program, Early Objects_12_PE_12_134.84
0131474340_Ralph Morelli_Java, Java, Java, Object-Oriented Problem Solving_3_PH_4_95.25
0596100469_Alex Martelli_Python in a Nutshell_2_OR_6_39.99
0134802217_Tony Gaddis_Starting Out with Java: From Control Structures through Objects_7_PE_8_118.67
1403946876_Sally Fincher_Studying Programming_1_PM_3_26.59
0596510047_Andy Oram_Beautiful Code: Leading Programmers Explain How They Think_1_OR_5_44.99
0143037889_Ray Kurzweil_The Singularity is Near: When Humans Transcend Biology_1_PG_20_17.70
0135205972_John Lewis_Java Foundations: Introduction to Program Design and Data Structures_5_PE_5_129.99
0131872893_Wanda Dann_Learning to Program with Alice_1_PH_12_47.50
159413962X_Dave Eggers_The Circle_1_AW_4_3.99
1887902996_John Zelle_Python Programming: An Introduction to Computer Science_1_FB_2_26.40
0133356728_Rafael Gonzales_Digital Image Processing_4_PE_3_248.17
1592400876_Lynne Truss_Eats, Shoots & Leaves_1_PG_5_17.70
0072823798_William Collins_Data Structures and the Java Collections Framework_2_MH_6_105.57
0072866098_Allen Tucker_Programming Languages: Principles and Paradigms_2_MH_1_127.50
0534950973_Michael Sipser_Introduction to the Theory of Computation_2_CT_3_98.90
0131496710_Francis Hill_Computer Graphics Using OpenGL 3rd Edition_3_PH_4_112.00
0321173486_Dave Shreiner_OpenGL Programming Guide_5_AW_1_24.00
0072865512_Steven Schach_Object Oriented and Classical Software Engineering_6_MH_9_123.44
0321228383_Michael Kifer_Database Systems: An Application-Oriented Approach_2_AW_3_112.86
1416587787_Cliff Stoll_The Cuckoo's Egg_1_PG_3_13.32
1400032717_Mark Haddon_The Curious Incident of the Dog in the Night-Time_1_VI_10_13.95
006025492X_Maurice Sendak_Where the Wild Things Are_1_HC_6_17.95
0694003611_Margaret Brown_Goodnight Moon_1_HC_138_8.99
069401298X_Arnold Lobel_Frog and Toad Together_1_HC_27_11.55
Last, but not least, I made an InventoryTester file to read the text file and print it using the code from both classes.
InventoryTester:
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import java.awt.Font;
import java.util.Scanner;
import java.io.*;
public class InventoryTester {
public static void main(String[] args) throws IOException {
Scanner inFile= new Scanner(new File("inventory.txt"));
Book books;
String inLine= inFile.nextLine();
int size= Integer.parseInt(inLine);
Inventory myInventory= new Inventory(size);
while (inFile.hasNext()) {
inLine= inFile.nextLine();
String ISBN = inFile.next();
String author = inFile.next();
String title = inFile.next();
int edition = inFile.nextInt();
String pubCode = inFile.next();
int quantity = inFile.nextInt();
double price = inFile.nextDouble();
myInventory.addBook(new Book(ISBN, author, title, edition, pubCode, quantity, price));
String[] tokens = inLine.split("_");
myInventory.printInventory();
}
inFile.close();
}
}
I was trying to make Java understand that there are strings, ints, and doubles. I'm trying to convert the text file using arrays into Strings, ints, and doubles. It should print, but the code considers it to be null. Am I missing something?
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Book.toString()" because "this.books[i]" is null
at Inventory.printInventory(Inventory.java:42)
at InventoryTester.main(InventoryTester.java:28)
----jGRASP wedge2: exit code for process is 1.
You could make a class to manage your inventory with an arraylist containing books. And then save that class in a binary file.
The class could look like this:
public class BookList implements Serializable
{
private ArrayList<Book> books;
public BookList()
{
books = new ArrayList<>();
}
public void addBook(Book book)
{
this.books.add(book);
}
public void removeBook(Book book)
{
this.books.remove(book);
}
public ArrayList<Book> getAllBooks()
{
return books;
}
And then save and load the file like this.
File file = new File("inventory.bin")
public void save(BookList bookList){
FileOutputStream out = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(bookList);
}
public BookList load(){
BookList bookList = null;
FileInputStream in = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(in);
bookList = (BookList) ois.readObject();
in.close();
ois.close();
}
Then you shouldn't have any trouble reading from the file.
REMEMBER! Both the list class and book class needs to implement Serializable.

How to remove duplication?

//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.

Adding objects to ArrayList [duplicate]

This question already has answers here:
Why does my ArrayList contain N copies of the last item added to the list?
(5 answers)
Closed 6 years ago.
This if my first question on stackoverflow. I can usually find answers myself but I'm having trouble with this one. I've got 2 objects, "Book", and "Periodical". These are subclasses to a class "Publication". Now, I'm trying to add 3 instances of "Book" and 3 instances of "Periodical" to an ArrayList. I'm having trouble figuring out how to do this.
With this current code, I get an error "no suitable method found for add(Book,Book,Book,Periodical,Periodical,Periodical).
Here is the current code:
import java.util.ArrayList;
import java.util.Date;
public class DriverProgram {
public static void main(String[] args) {
// Instantiate 3 instances of each object.
Book book1 = new Book(1234, 1, "James", 100, "Hello", "Berkwood Inc.", new java.util.Date(), "History");
Book book2 = new Book(2345, 2, "Ralph", 200, "Goodbye", "Shackles Co.", new java.util.Date(), "English");
Book book3 = new Book(3456, 3, "Julia", 300, "Hello Again", "Trustin Inc.", new java.util.Date(), "History");
Periodical periodical1 = new Periodical("Daily", "Dylan", "History 101", "History Inc.", new java.util.Date(), "History");
Periodical periodical2 = new Periodical("Weekly", "Jannette", "Mathematics 101", "Mathematics Inc.", new java.util.Date(), "Mathematics");
Periodical periodical3 = new Periodical("Monthly", "Patricia", "Science 101", "Science Inc.", new java.util.Date(), "Science");
// Create an array list of the Publication class type, and add the objects to it.
ArrayList <Publication> publications = new ArrayList<Publication>();
publications.add(book1, book2, book3, periodical1, periodical2, periodical3);
// Pass the array list to a method to loop through it and display the toString methods.
displayObjects(publications);
} // End of main
static void displayObjects (ArrayList<Publication> publications) {
// Loop through array list and display the objects using the toString methods.
for (Publication p : publications) {
System.out.print(p.toString());
} // End of for each loop
} // End of displayObjects
} // End of DriverProgram class
I've also tried changing:
publications.add(book1, book2, book3, periodical1, periodical2, periodical3);
To this:
publications.add(book1);
publications.add(book2);
publications.add(book3);
publications.add(periodical1);
publications.add(periodical2);
publications.add(periodical3);
Which rids my program of the compiler error, but then it just prints the "periodical3" object, 6 times. I'm not sure what I'm doing wrong. Any suggestions? Thank you in advance! :)
EDIT:
Here is my Book class:
public class Book extends Publication{
private static int isbn = 0;
private static int libraryOfCongressNbr = 0;
private static String author = "";
private static int nbrOfPages = 0;
// Constructor for Book class with parameters for each attribute.
public Book(int newISBN, int newLibraryOfCongressNbr, String newAuthor, int newNbrOfPages, String newTitle, String newPublisher, java.util.Date newPublicationDate, String newSubject) {
super(newTitle, newPublisher, newPublicationDate, newSubject);
isbn = newISBN;
libraryOfCongressNbr = newLibraryOfCongressNbr;
author = newAuthor;
nbrOfPages = newNbrOfPages;
}
/////////////////////////////////////////////////////// Getters ///////////////////////////////////////////////////////
int getISBN() {
return isbn;
}
int getLibraryOfCongressNbr() {
return libraryOfCongressNbr;
}
String getAuthor() {
return author;
}
int getNbrOfPages() {
return nbrOfPages;
}
/////////////////////////////////////////////////////// Setters ///////////////////////////////////////////////////////
void setISBN(int newISBN) {
isbn = newISBN;
}
void setLibraryOfCongressNbr(int newLibraryOfCongressNbr) {
libraryOfCongressNbr = newLibraryOfCongressNbr;
}
void setAuthor(String newAuthor) {
author = newAuthor;
}
void setNbrOfPages(int newNbrOfPages) {
nbrOfPages = newNbrOfPages;
}
//toString method for Book class
public String toString () {
StringBuilder result = new StringBuilder();
result.append("\nISBN: " + isbn + "\n");
result.append("\nPublisher: " + libraryOfCongressNbr + "\n");
result.append("\nAuthor: " + author + "\n");
result.append("\nNumber of Pages: " + nbrOfPages + "\n");
result.append("--------------------------------------------------------- ");
return super.toString() + result.toString();
} // End of toString
} // End of Book class
My Periodical class is identical, but here is my Publication class:
import java.util.Date;
public abstract class Publication {
// Data fields.
private static String title = "";
private static String publisher = "";
private static java.util.Date publicationDate;
private static String subject = "";
// Constructor for Publication class with parameters for each attribute.
public Publication(String newTitle, String newPublisher, java.util.Date newPublicationDate, String newSubject){
title = newTitle;
publisher = newPublisher;
publicationDate = newPublicationDate;
subject = newSubject;
}
/////////////////////////////////////////////////////// Getters ///////////////////////////////////////////////////////
String getTitle() {
return title;
}
String getPublisher() {
return publisher;
}
java.util.Date getPublicationDate() {
return publicationDate;
}
String getSubject() {
return subject;
}
/////////////////////////////////////////////////////// Setters ///////////////////////////////////////////////////////
void setTitle(String newTitle) {
title = newTitle;
}
void setPublisher(String newPublisher) {
publisher = newPublisher;
}
void setPublicationDate(java.util.Date newPublicationDate) {
publicationDate = newPublicationDate;
}
void setSubject(String newSubject) {
subject = newSubject;
}
//toString method for Publication class
public String toString () {
StringBuilder result = new StringBuilder();
result.append("\nTitle: " + title + "\n");
result.append("\nPublisher: " + publisher + "\n");
result.append("\nPublication Date: " + publicationDate + "\n");
result.append("\nSubject: " + subject + "\n");
return result.toString();
} // End of toString
} // End of Publication class
Let me know if you need anything else!
EDIT x2: Sorry, I realize my post is getting quite long.
So I've gotten rid of all "static" keywords from my class variables, or "data fields" as I've called them in my code. I then changed my code back to this code:
ArrayList <Publication> publications = new ArrayList<Publication>();
publications.add(book1);
publications.add(book2);
publications.add(book3);
publications.add(periodical1);
publications.add(periodical2);
publications.add(periodical3);
And it works! It executes as it should! I just one question though, since this code doesn't seem to work:
publications.add(book1, book2, book3, periodical1, periodical2, periodical3);
Is there a shorter way to add all of the objects to the ArrayList with out doing it one by one?
If I understand the problem correctly, you have 6 Publication objects, and you are only seeing the values of the most recently created one.
That would likely be caused because you have static class variables instead of instance variables.
For example
class A {
static int x; // class variable
int y; // instance variable
public A(int val) {
x = val; // All 'A' classes now have x = val;
y = val; // Only 'this' class has y = val;
}
}
If I were to run this
A a1 = new A(4);
A a2 = new A(5);
System.out.println(a1.x);
Then I would see it print 5 and not 4, which describes the scenario you are seeing because you have assigned all variables in the Publication class to those that you use during the last call of new Periodical.
The solution is to not use static variables if you want to have multiple instances of a class with their own values.

Set / Get methods, tostring & ask method - Java

I am reletively new to java and have been set some tasks to complete, I (think) I have completed the first two tasks which request I:
Design a class Manual with the following properties:
serial number - string, - default:??????
title - string, - default: Untitled
author - string, - default: Unknown
Write a constructor and a method to print details of a Manual on the console.
.
Amend your Manual class by writing the following additional methods:
methods to set and get the properties of a Manual
a method to ask the user for details of a Manual
a toString() method.
Write a simple application to test your additional methods.
"
So far, I have this code:
public class Manual {
String serialNumber, title, author;
public static void main(String [] args){
Manual man= new Manual();
man.print();
}
public Manual(){
set("??????", "Untitled", "Unknown");
}
public Manual(String serialNumber, String title, String author)
{
set(serialNumber, title, author);
}
public void set(String serialNumber, String title, String author)
{
this. serialNumber = serialNumber;
this. title = title;
this.author = author;
}
public void print()
{
System.out.println("Serial Number : " +serialNumber);
System.out.println("Title : " +title);
System.out.println("Author : " +author);
}
public void print(String heading)
{
System.out.println(heading);
print();
}
public void ask()
{
serialNumber = Console.askString("Please enter the serial number: ");
title = Console.askString("Please enter the title: ");
author = Console.askString("Please enter the author: ");
set(serialNumber, title, author);
}
public String toString()
{
return serialNumber +" " +title +" " +author +" ";
}
}
Would anyone kindly be able to inform me if I have completed all areas of the first two questions correctly, and if there are any mistakes present in my code?
Thank you
The only major issue I see is that you have not implemented the Getters and Setters as was probably intended. In Java most classes have Getters/Setters for each variable that needs to be accessed, something like:
public String getTitle()
{
return title;
}
public void setTitle(String _title)
{
this.title = _title;
}
Also, there is nothing "wrong" with the way you have done the Print and toString functions, but I would have written up the toString to output more similar to how you have print doing it, and then calling toString from the print. Something like:
public String toString()
{
return "SerialNumber: " + serialNumber +"\n"
+"Title: " + title + "\n"
+"Author: " + author +"\n";
}
public void print()
{
System.out.println(this.toString());
}
As a final note, you did not include any code to use this class, as mentioned in the last line of question 2. Hope this helps
This is how I would implement the get() method for all three variables.
public String getSerialNumber(){
return serialNumber;
}
public String getTitle(){
return title;
}
public String getAuthor(){
return author;
}

Categories