bookTest.java prints out author arrayList, but not isbn - java

Requirements: accommodate multiple authors using one of the components from the Java Collection Framework. Requires one book with an isbn and a Collection of authors. JUnit: Guidance for testValidate: Test for at least two cases (one case where the book properties hold the correct data types and are not empty nor hold a null value, one where they do not). Guidance for testEquals: Test for at least two cases (one case where authors and isbn match, one where they do not). Test for at least two authors. My teacher told me: testEquals you need to add isbn and two authors. Create an ArrayList. Add two authors to it. Create a Book object and add the ArrayList instance and the isbn. I think that's what I have done, the authors are printing, but the ISBNs are not. I am a total newbie and I am at a loss! Can anyone help?
EDIT/ADDITION I got the ISBN to print, but it is only printing the second isbn I have. What do I need to change to get both of them to print? Or does it matter?
Here is the output:
Testsuite: library.domain.BookTest
equals
Author List: [Bob Smith, Jane Doe]
ISBN: 67890
validate
Author List: [Bob Smith, Jane Doe]
ISBN: 67890
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.23 sec
------------- Standard Output ---------------
equals
Author List: [Bob Smith, Jane Doe]
ISBN: 67890
validate
Author List: [Bob Smith, Jane Doe]
ISBN: 67890
------------- ---------------- ---------------
test:
Deleting: /var/folders/k7/wpgy3lw91171qxlzt4pj0cfh0000gn/T/TEST-library.domain.BookTest.xml
BUILD SUCCESSFUL (total time: 1 second)
Here is my new page:
NEW BookTest.java
package library.domain;
import java.util.ArrayList;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class BookTest {
private ArrayList<String> authorList = new ArrayList<>();
#Test
public void testEquals() //test Equals() for accuracy
{
System.out.println("equals");
authorList.add("Bob Smith");
Book book = new Book("12345", authorList);
assertEquals("expected true", true, book.equals(book));
authorList.add("Jane Doe");
book = new Book("67890", authorList);
assertEquals("expected true", true, book.equals(book));
System.out.println("Author List: " + authorList);
System.out.println("ISBN: " + book.getIsbn());
}
#Test
public void testValidate() //test Validate() for accuracy
{
System.out.println("validate");
authorList.add("Bob Smith");
Book book = new Book("12345", authorList);
assertEquals("expected true", true, book.validate());
authorList.add("Jane Doe");
book = new Book("67890", authorList);
assertEquals("expected true", true, book.validate());
System.out.println("Author List: " + authorList);
System.out.println("ISBN: " + book.getIsbn());
}
}
Book.java
package library.domain;
import java.util.ArrayList;
import java.util.Objects;
public class Book {
private String isbn;
private ArrayList<String> authorList;
public Book(String isbn, ArrayList<String> authorList)
{
this.isbn = isbn;
this.authorList = authorList;
}
public String getIsbn() //access to isbn and manages next value
{
return isbn;
}
public void setIsbn(String isbn) //assigns the input isbn to the data member isbn
{
this.isbn = isbn;
}
//assigns the input author to the data member author
public ArrayList<String> getAuthorList()
{
return authorList;
}
public void setAuthorList(ArrayList<String> authorList)
{
this.authorList = authorList;
}
#Override
public boolean equals(Object obj) //checks equality of two objects - true if same, false if different
{
if (this == obj) {
return true;
}
if (!(obj instanceof Book)) {
return false;
}
Book book = (Book) obj;
if (!this.isbn.equals(book.isbn)) {
return false;
}
if (!this.authorList.equals(book.authorList)) {
return false;
}
return true;
}
#Override
public int hashCode() //override hash
{
int hash = 7;
hash = 97 * hash + Objects.hashCode(this.authorList);
hash = 97 * hash + Objects.hashCode(this.isbn);
return hash;
}
public boolean validate() //validate isbn and author not null
{
if (isbn == null || isbn.equals("")) {
return false;
}
if (authorList == null || authorList.equals("")) {
return false;
}
{
return true;
}
}
}
BookTest.java
package library.domain;
import java.util.ArrayList;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class BookTest {
private ArrayList<String> authorList = new ArrayList<>();
private String isbn;
#Test
public void testEquals() //test Equals() for accuracy
{
System.out.println("equals");
authorList.add("Bob Smith");
authorList.add("Jane Doe");
Book book = new Book("12345", authorList);
assertEquals("expected true", true, book.equals(book));
System.out.println("Author List: " + authorList);
System.out.println("ISBN: " + isbn);
}
#Test
public void testValidate() //test Validate() for accuracy
{
System.out.println("validate");
authorList.add("Bob Smith");
authorList.add("Jane Doe");
Book book = new Book("12345", authorList);
assertEquals("expected true", true, book.validate());
System.out.println("Author List: " + authorList);
System.out.println("ISBN: " + isbn);
}
}

isbn in the test class is a local variable and you are not setting any values for the same. To check if object is being created correctly, try printing book.getAuthorList() and book.getIsbn()

In BookTest you are printing out the value of the isbn in the scope of BookTest. You initialized it in BookTest so any calls to isbn will refer to the global variable
private String isbn;
You need to print out the isbn field of the Book object.
System.out.println("ISBN: " + book.getIsbn());
You had the getter method written, you just forgot to use it.

When accessing the ISBN and authorList you should use their getter methods. In your test there is no String object named ISBN. Instead use book.getIsbn();
Some other things:
In the validate() method; authorList is a List not a String so authorList.equals("") will never return true. You should do something like authorList.size() == 0. Also the return true doesn't need to be within {}.
Also you shouldn't just try to print a list (System.out.println("Author List: " + authorList);). You could get very unexpected results.

Book book = new Book("12345", authorList);
Here you are setting value to isbn is available in Book class.
System.out.println("ISBN: " + isbn);
But here you are trying print isbn which is present in current class. So it doesn't print any value. Since you are not pass any value to it.
To print value of isbn, available in Book class write
System.out.println("ISBN: " + book.getIsbn());
System.out.println("Author List: " + authorList);
Here also authorList is a local variable. To print value of authorList is available in Book class wirte
System.out.println("Author List: " + book.authorList());

Related

Having trouble with displaying boolean in Java

This is my first exercise with boolean. I need to display the output for car_Type whether it's a national car or imported car. The main class was already compiled successfully but when i run it and type in the input it says "Exception in thread "main" java.util.InputMismatchException". Here's the main class:
import java.util.Scanner;
public class CarApp
{
public static void main(String[] args)
{
//declaration
Scanner input = new Scanner(System.in);
String model, brand;
double price;
boolean type;
Car c = new Car();
System.out.println("Enter a car Model : ");//X70/Starex
model = input.nextLine();
System.out.println("\nEnter a car Brand : ");//Proton/Hyundai
brand = input.nextLine();
System.out.println("\nEnter the car price : RM");//95000.00/170000.00
price = input.nextDouble();
System.out.println("\nEnter the car brand [national/imported] : ");//national/imported car
type = input.nextBoolean();
//output
System.out.println("Car Model : "+model);
}
}
Also, here's the car class if you want to check on the error:
public class Car
{
String car_Model;
String car_Brand;
double car_Price;
boolean car_Type;
public Car()
{
car_Model = " ";
car_Brand = " ";
car_Price = 0.0;
car_Type = true;
}
public Car(String cm, String cb, double cp, boolean ct)
{
car_Model = cm;
car_Brand = cb;
car_Price = cp;
car_Type = ct;
}
void SetCar_Model(String cm){
car_Model = cm;
}
void SetCar_Brand(String cb){
car_Brand = cb;
}
void SetCar_Price(double cp){
car_Price = cp;
}
void SetCar_Type(boolean ct){
car_Type = ct;
}
String GetCar_Model()
{
return car_Model;
}
String GetCar_Brand()
{
return car_Brand;
}
double GetCar_Price()
{
return car_Price;
}
Boolean GetCar_Type()
{
return car_Type;
}
public String toString()
{
return "Car Model : " +car_Model + "\nCar Brand : " +car_Brand + "\nCar Price : " +car_Price + "Car Type : " +car_Type;
}
}
Here's the input:
Enter a car Model :
X70
Enter a car Brand :
Hyundai
Enter the car price : RM
95000.00
Enter the car brand [national/imported] :
national
And after i click enter it shows:
Exception in thread "main" java.util.InputMismatchException
at java.base/java.util.Scanner.throwFor(Scanner.java:939)
at java.base/java.util.Scanner.next(Scanner.java:1594)
at java.base/java.util.Scanner.nextBoolean(Scanner.java:1893)
at CarApp.main(CarApp.java:23)
Thank you for your help!
Java boolean data type, can only take the values true or false.
national can't be parsed as a boolean. You have to parse it yourself according to your logic. You could name the field for example isNational and set it to true if the user entered national and false if imported was entered. In your toString method you can then either return "imported" or "national" according to the boolean of isNational like so
isNational ? "national" : "imported"
this is called a ternary operator.
Also think about what should happen if the user enters neither one of those two choices.
You don't need to declare all your variables at the top of the method and then assign them below. Most of the time, if it's deterministic which value gets assigned you can assign it at the time of declaration.
And lastly: usually Java fields are written in camelCase. Take a look on Java naming conventions here.

I am getting unexpected behaviour when using Java Streams and Scanners

I recently saw a topic of some Uni coursework which was being conducted by a friend whom was instructed to do it a certain way. I thought I'd take the opportunity to jump in on the task.
I created a Book class like so:
class Book
{
private String author, title;
public Book setAuthor(String a)
{
author = a;
return this;
}
public Book setTitle(String t)
{
title = t;
return this;
}
public String getAuthor()
{
return author;
}
public String getTitle()
{
return title;
}
}
The concept is that a user can create multiple books at the start of the program and then search for an author:
private final static int BOOK_NO = 3;
private final static SO instance = new SO(); // This is whatever you called the class
public static void main(String[] args)
{
Book[] books = new Book[BOOK_NO];
Scanner kybd = new Scanner(System.in);
for(int i = 0; i < BOOK_NO; i++)
{
books[i] = instance.addBook(kybd, new Book());
}
Arrays.stream(instance.findBook(kybd, books)).forEach(o -> {
System.out.println(o.getTitle() + " by " + o.getAuthor());
});
}
public Book addBook(Scanner s, Book b)
{
System.out.println("Enter the Author of this book:");
b.setAuthor(s.next());
System.out.println("Enter the Title of this book:");
b.setTitle(s.next());
return b;
}
public Book[] findBook(Scanner s, Book[] bs)
{
System.out.println("Search a book by author:");
List<Book> finding = Arrays .stream(bs)
.filter(o -> o.getAuthor().equalsIgnoreCase(s.next()))
.collect(Collectors.toList());
System.out.println("Found " + finding.size() + " matches.");
Book[] output = new Book[finding.size()];
output = finding.toArray(output);
return output;
}
Now the whole program works fine, however I am experience unexpected behaviour with the Scanner when it comes to searching for a book. Here is a direct input/output behaviour I am experiencing:
Enter the Author of this book:
Foo
Enter the Title of this book:
Bar
Enter the Author of this book:
Foo
Enter the Title of this book:
FooBar
Enter the Author of this book:
Bar
Enter the Title of this book:
Foo
Search a book by author:
Foo
Foo
Foo
Found 2 matches.
Bar by Foo
FooBar by Foo
As you can see, I am having to type the author of the book into the scanner 3 times before getting any result. How can I mitigate this? What is causing this to happen?
This is because in your Stream you call next(), so for every Book object in the Stream, the Predicate in the call to filter is applied to it, and next() will be called. Resolve it to a variable so it isn't called more than once:
String book = s.next();
List<Book> finding = Arrays.stream(bs)
.filter(o -> o.getAuthor().equalsIgnoreCase(book))
.collect(Collectors.toList());
filter() accepts a Predicate, which in this case will be something like:
Predicate<String> pred = str -> str.equalsIgnoreCase(s.next());
So every time it is applied, next() will be called

indexOf in Java - ArrayList

import java.util.ArrayList;
import java.util.Scanner;
public class JavaApplication10Arraylistandobjects {
static Scanner user_input = new Scanner(System.in);
public static void main(String[] args) {
test();
}
public static void test(){
ArrayList<mainclass> me = new ArrayList <> ();
mainclass ob;
for (int i=0;i<2;i++){
ob = new mainclass();
System.out.println("name");
ob.name = user_input.nextLine();
System.out.println("sname");
ob.sname = user_input.nextLine();
me.add(ob);
}
System.out.println("Show List: " + me);
System.out.println("Confirm if is true or false: " + me.get(1).toString().contains("max"));
System.out.println("what is index of: " + me.get(1).toString().indexOf("max"));
}
}
public class mainclass {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
#Override
public String toString() {
return "mainclass{" + "name=" + name + ", sname=" + sname + '}';
}
String name;
String sname;
}
My questions is how can I find correctly indexOf string.
For example when I am checking if string "max" exist - it shows me "true"
and when I am trying to find index of string "max" it shows me index 15 which is not correct.
P.S. I found an article with the same problem where it says that I have to override equals and hashcode - I've done it but anyway I got the same problem.
Please point me to the right direction.
What I am doing wrong here, can someone explain me pls.
These are my inputs and output.
run:
name Jony
sname Bravo
name max
sname hitman
Show List:[mainclass{name=Jony, sname=Bravo}, mainclass{name=max, sname=hitman}]
Confirm if is true or false: true
what is index of: 15
BUILD SUCCESSFUL (total time: 11 seconds)
The line:
System.out.println("what is index of: " + me.get(1).toString().indexOf("max"));
has a problem, in that you're getting the object in the me list at index 1, getting its toString(), and looking for "max" in there. What you actually want to do, as I understand it, is look through the me list and find the place in the list with "max" in it.
P.S. I found an article with the same problem where it says that I have to override equals and hashcode - I've done it but anyway I got the same problem.
If you did that, it would allow you to do something like this:
x = new mainclass();
x.setName("Max");
System.out.println("what is index of: " + me.indexOf(x));
However, there's still a potential problem. Unless you set your equals() and hashCode() to only look at the name and not also sname, then it's not going to find anything unless the sname also matches.

HashSet - ensuring the earlier object persistence

I have to use a HashSet where a lot of duplicate value may be inserted. But I want to preserve the earlier data inserted in the hash when a later insertion makes the duplicate. To examine this I have write the following code and insert many duplicate value, but it doesn't satisfy me. Please see the code below -
import java.util.HashSet;
import java.util.Set;
public class SetTest {
private static Set<Student> studentSet = new HashSet<Student>();
private static Student s1, s2, s3, s4, s5, s6, s7, s8, s9;
public static void main(String args[]){
s1 = new Student(1, 1, "Syeful", "first boy");
s2 = new Student(2, 2, "Razib", "no comments");
s3 = new Student(3, 3, "Bulbul", "should remain");
s4 = new Student(4, 3, "Bulbul", "should not remain");
s5 = new Student(5, 4, "Bulbul", "should remain");
s9 = new Student(9, 5, "Proshanto", "kaka - my favourite");
studentSet.add(s1);
studentSet.add(s2);
studentSet.add(s3);
studentSet.add(s4);
studentSet.add(s5);
studentSet.add(s9);
for(Student each : studentSet){
System.out.println("SrNo: " +each.getSrNo()+ " roleNo: "
+each.getRoleNo()+ " name: " +each.getName()+
" coment: " +each.getComment());
}
}
}
class Student{
private int srNo;
private int roleNo;
private String name;
private String comment;
public Student(int srNo, int role, String name, String comment) {
super();
this.srNo = srNo;
this.roleNo = role;
this.name = name;
this.comment = comment;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + roleNo;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Student)) {
return false;
}
Student other = (Student) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
if (roleNo != other.roleNo) {
return false;
}
return true;
}
public int getSrNo() {
return srNo;
}
public int getRoleNo() {
return roleNo;
}
public String getName() {
return name;
}
public String getComment() {
return comment;
}
}
And the output is:
Set Size: 5
SrNo: 9 roleNo: 5 name: Proshanto coment: kaka - my favourite
SrNo: 2 roleNo: 2 name: Razib coment: no comments
SrNo: 1 roleNo: 1 name: Syeful coment: first boy
SrNo: 5 roleNo: 4 name: Bulbul coment: should remain
SrNo: 3 roleNo: 3 name: Bulbul coment: should remain
It seems me to clarify some points before asking the questions so that I can explain it properly and clarify my understanding as well.
I want to maintain the uniqueness of 'Student' based on roleNo and name.That's why the hashCode() and equals() role is made up with these property. So according to this implementation s3 and s4 are duplicate of each other even thought the comment , srNo property of them differs from each other.
HashSet is unordered.
When s4 is added in the set, we can see from the out put that s4 is discarded from the set and s3 remains.
Suppose I want to add another object of student s100 = new Student(3, 3, "Bulbul", "earlier instance suppressed"); which is the duplicate of s3. Let we have inserted a lot of duplicate of s3 before inserting s100.
Question:
Since set is unsorted and the duplicate dose not exist in set, is there any possibility that the s3 is removed by s100? I want to persist the earlier object discarding the later one. The small amount of data is not clarifying the fact. I think in this case a sorted Set may used. But does the HashSet can serve the purpose?
Thanks in advance.
HashSet.add(E e) leaves the set unchanged if it already contains the specified element. So, there are no circumstances where s3 would be removed by s100.
If you do not want collisions in your set, you need to redefine your hashing function to include more data in it, such as getSrNo. Relational Databases traditionally perform this using a unique primary key which is automatically generated for every new entry. This of "StudentID" or something like that, which should be unique across the school.

Java Retrieve or Remove a value from TreeMap

I have a problem retrieving a Student's info from a list, or deleting it... Heelp... Code below:
import java.util.*;
public class Directory
{
private TreeMap<String, Student> studentList;
private int numberOfEntries;
public Directory()
{
studentList = new TreeMap<String, Student>();
numberOfEntries = 0;
}
public void addStudent(Student newStudent)
{
studentList.put(newStudent.StudentInfo(), newStudent);
//numberOfEntries++;
}
public void StudentInfo(String StudentInfo)
{
Object obj = studentList.get(StudentInfo);
System.out.println(obj);
}
public void removeStudent(String StudentInfo)
{
Object obj = studentList.remove(StudentInfo);
System.out.println(obj + "Removed");
}
public void printStudentList()
{
System.out.println("List of Students: " + studentList.keySet());
}
}
======= Student class ======== (Persons contains first, last & email)
public class Student extends Persons
{
private String Sclass;
public Student(String Lname, String Fname, String Email, String Sclass)
{
super(Lname, Fname, Email);
this.Sclass = Sclass;
}
public String StudentInfo()
{
return " Full Name " + Lastname + " " + Firstname + "\n" +
"E-Mail: " + Email + "\n" +
"Class Attending: " + Sclass;
}
public String getName()
{
return Lastname;
}
}
I could try and debug this for you, but that would defeat the purpose. (This is your homework ... and the purpose is for you to learn how to do this yourself.)
My advice is as follows:
FIRST fix the style errors:
The names of variables should always start with a lower-case letter ... unless they are static final constants.
The names of methods should always start with a lower-case letter
Method and variable names should also be meaningful and consistent. For instance:
public void removeStudent(String StudentInfo)
Here StudentInfo actually needs to a student name, not a "student info" string as created by the StrudentInfo method ...
Another example: lname and fname are not meaningful. (I can guess what they mean, but that is not good enough.)
Create yourself a tester program that created instances of those classes and performs a sequence of tests on them. Start with simple things, then move on the more complicated ones.
(In the real world, we'd set up a more formal set of "unit tests" ... but you are probably not ready for that yet.
In fact, if you choose more meaningful names, and then look carefully at how those names are used, your error should "leap out and hit you on the nose".
But you will get maximum benefit if you go through the process yourself.

Categories

Resources