Search ArrayList object : object's - java

I struggled to find a solution or at least to point me in the right direction...
Here is my ArrayList: books = new ArrayList();
I have to search objects of Book that contain a title(String). Here is what I have..
The problem being is that I only want to print the second statement if it is not found. But it seems to be printing it as it searches each object in the list?
public void searchBookInCollection(String title)
{
for (Book book : books)
{
if(book.getTitle().equalsIgnoreCase(title))
{
book.displayBookInformation();
}
else
{
System.out.println("Nope we don't have it");
}
}
}

change it to have a boolean found flag
public void searchBookInCollection(String title)
{
boolean found = false;
for (Book book : books)
{
if(book.getTitle().equalsIgnoreCase(title))
{
book.displayBookInformation();
found = true;
break; // no point to keep going?
}
}
if (!found)
{
System.out.println("Nope we don't have it");
}
}

Since the method says searchBookInCollection() it is expected to return a book or a name or something. This gives an alternative solution,
public String findBook(String title) { // "InCollection" does not help end user, "find" follows standard naming convention
for (String book : books) {
if (book.equalsIgnoreCase(title)) {
return book; // This is debated, if you want "one return" here, use temporary variable.
}
}
throw new NoSuchElementException("Title was not found!"); // Throw gives the end user a chance to handle the exception.
}

Related

ArrayChecker failure?

I have a problem with the following code:
Import java.util.ArrayList;
public class Car {
private String car;
private Car genCar = new Car();
ArrayList<String> allCars = new ArrayList<>();
public void setCar() {
genCar.setModel();
genCar.setCreator();
car = genCar.getModel() + "made by" + genCar.getCreator();
}
public void checkDouble() {
for (String search : allCars) {
while (search.equals(car)) {
setCar();
}
}
allCars.add(car);
}
public void repeater(){
for(int i = 0; i<52; i++){
setCar();
checkDouble();
}
}
}
Whenever I try to check for duplicates (which this code does) my program still puts the duplicate in the array when I actually try to avoid it this way.
Any solution so this works?
You do this:
public void checkDouble()
{
for (String search : allCars)
{
while (search.equals(car))
{
setCar();
}
}
allCars.add(car);
}
The problem with this is that, once you found a double, you generate a new car using setCar(), but you do not search the entire list again.
Do something like:
public void avoidDoubles()
{
while allCars.contains(car)
{
setCar(); // generate new, different car
}
allCars.add(car);
}
FWIW, you might want to change the name of some of the functions. I would call setCar() generateNewCar() or newCar().
I'm not sure what you're trying to do, but in checkDouble you are finding a duplicate and then adding it to the list.
If I understand you correctly, you don't need the loops, All you need to do is to use ArrayList.contains()
if(allCars.contains(someString))
{
System.err.println("Duplicate...");
} else
{
//setCar, addCar, etc.
}

How to write nested for loops in methodes (clean code)

Clean code means for me: only one task for each methode and no nested loops.
When I got the following code, I asked myself, how can I avoid nested for loops and encapsulate them in methods.
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
for (Option option : getOptions(context)) {
for (Group group : getGroups()) {
if (option.getValue().equalsIgnoreCase(group.getName())) {
return group.getUser();
}
}
}
}
return "default";
}
My first solution was the following. The problem here is, the for loops are running until the end and do not break (return) when the value is found and set.
private String user = "default";
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
processOptions(context);
}
return this.user;
}
private void processOptions(FieldConfigScheme context){
for (Option option : getOptions(context)) {
processGroups(option);
}
}
private void processGroups(Option option){
for (Group group : getGroups()) {
setUser(option, group);
}
}
private void setUser(Option option, Group group){
if (option.getValue().equalsIgnoreCase(group.getName())) {
this.user = group.getUser();
}
}
so I wrote this code, which should be the same like the first:
private String user = "default";
private boolean isUserSet = false;
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
if(!isUserSet) processOptions(context);
else return this.user;
}
return this.user;
}
private void processOptions(FieldConfigScheme context){
for (Option option : getOptions(context)) {
if(!isUserSet) processGroups(option);
else return;
}
}
private void processGroups(Option option){
for (Group group : getGroups()) {
if(!isUserSet) setUser(option, group);
else return;
}
}
private void setUser(Option option, Group group){
if (option.getValue().equalsIgnoreCase(group.getName())) {
this.user = group.getUser();
isUserSet = true;
}
}
But then I asked myself, is this really better code? Is this more clean code? Yes, every method is only doing one thing. And yes, the code is better to read in my opinion. But from originally 12 lines compact code I now got 30 lines of code and one member variable more in the code. So is the first originally code better because it's more compact even with nested for loops?
What do you think? Which one is better? Or how can I write the code better?
Thanks in advance for your answers!
Instead of returning void, why not boolean?
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
if (processOptions(context)) {
break;
}
}
return this.user;
}
private boolean processOptions(FieldConfigScheme context){
for (Option option : getOptions(context)) {
if (processGroups(option)) {
return true;
}
}
return false;
}
private boolean processGroups(Option option){
for (Group group : getGroups()) {
if (option.getValue().equalsIgnoreCase(group.getName())) {
this.user = group.getUser();
return true;
}
}
return false;
}
T.B.H. I prefer the nested loops method. It looks clean, there is nothing more going on in the loop than to simply find something in a hierarchy and this is perfectly fine.
The use of extra function in this case is just bad. Imagine having to debug this code now, rather than focusing on one method which is doing this, you will have to look at all the extra ones you made.
Also this method doesn't seem to take any parameters which suggests that it actually only needs to do this check once and the rest of the time it should just return the same value. That just a guess, but if that was the case, then it makes your efforts to make it cleaner all the more unnecessary.

Calling a method for another object and class' method, inside a method (Java)

I have a class, LazyAuthor, that stores information about an author and can have a 'rival' (another object of the same class) set for it, and various methods cause them to interact with each other. The LazyAuthor class also relies on another class Book which stores details of the book's title, etc.
I am trying to set up a method rivalsLastTitle that returns the title (from the corresponding Book object) for the rival's last book. I have written this as:
public String rivalsLastTitle(){
return currentRival.getLastBook().getTitle();
}
where the corresponding methods I've called are
public Book getLastBook(){
return lastBook;
}
from the LazyAuthor class and
public String getTitle(){
return title;
}
from the Book class. currentRival is an object of the LazyAuthor class.
However this is returning a null value so clearly my syntax is wrong. I'm not sure how to write this code in order for it to return the title of the rival's lastBook object. I believe I may be overcomplicating the instruction for the return statement but I have seen multiple method calls like this work before.
Any help would be appreciated, I would be happy to share other parts of the code if that's useful. Thank you
edit: Here is the code for the whole LazyAuthor class. Apologies for length:
// fields (data members) go here
private int currentMoney, newMoney;
private String authorName, name;
private Book lastBook, bestBook, rLastBook, newBook, newLastBook,newBestBook, nextBook;
private LazyAuthor currentRival, newRival;
private boolean happy, jealous, lol;
// methods go here
public LazyAuthor(String name){
authorName = name;
currentMoney = 10000;
}
//set methods
public void setLastBook(Book newLastBook){
lastBook = newLastBook;
}
public void setBestBook(Book newBestBook){
bestBook = newBestBook;
}
public void setRival(LazyAuthor newRival){
newRival = currentRival;
}
public void setMoney(int newMoney){
newMoney = currentMoney;
}
public void setName(String name){
name = authorName;
}
//get methods
public Book getLastBook(){
return lastBook;
}
public Book getBestBook(){
return bestBook;
}
public int getMoney(){
return currentMoney;
}
public String getName(){
return authorName;
}
public LazyAuthor getRival(){
return currentRival;
}
// complex methods
public String lastTitle(){
return lastBook.getTitle();
}
public String bestTitle(){
return bestBook.getTitle();
}
public String rivalsLastTitle(){
rLastBook = currentRival.getLastBook();
return rLastBook.getTitle();
}
public boolean isHappy(){
// happy if last book written is their best OR they sold film rights for it
if(lastBook == bestBook || lastBook.filmRightsAreSold() == true) {
happy = true; }
else {
happy = false; }
return happy;
}
public boolean isJealous(){
// jealous if their rival's last book made more money, but isn't jealous if they managed to sell film rights for their last book
rLastBook = currentRival.getLastBook();
if(rLastBook.getValue() > lastBook.getValue() ){
jealous = true; }
else {
jealous = false;}
if(lastBook == bestBook || lastBook.filmRightsAreSold() == true) {
jealous = false; }
return jealous;
}
public boolean laughsAboutRival(){
// they laugh if their rival didn't sell film rights for their last book or if it made less than their own
rLastBook = currentRival.getLastBook();
if(rLastBook.filmRightsAreSold() == false || currentRival.getLastBook().getValue() < lastBook.getValue()) {
lol = true; }
else {
lol = false;}
return lol;
}
public void buyBackRightsOfLastBook(){
if(lastBook.filmRightsAreSold() == true && currentMoney >= lastBook.getBuyBackCost() ){
setMoney(currentMoney - lastBook.getValue() );
lastBook.buyBackRights(); }
}
public void writeNewBook(Book newBook){
// writes new book only if their last book wasn't their best, and they didn't sell the rights to it.
if(lastBook!=bestBook && lastBook.filmRightsAreSold() == false && currentMoney < lastBook.getValue() ){
lastBook = newBook;
currentMoney= currentMoney + lastBook.getValue();
}
}
edit 2: having just looked over the code again while editing this post, I seem to have assigned the labels in some of the set methods the wrong way around. I'm editing this now and will see if this fixes the null pointers.
edit 3: this seems to have worked, thank you all for the reassurance that my original syntax was correct and also for clarification on what a null value implies has gone wrong :)

Java - Input Verifier

I was just creating this specific but I was a little confused on documenting this. Am just stuck on explaining what the last couple of lines do :
class MyVerifier extends InputVerifier {
public boolean verify(JComponent input) {
if (input==id) {
return validId();
}
else if (input==name) {
return validName();
}
return false;
}
public boolean validId() {
boolean status;
String theID = id.getText();
Pattern pattern = Pattern.compile("\\d{8}");
Matcher matcher = pattern.matcher(theID);
if (matcher.matches()) {
status = true;
}
else {
status = false;
}
return status;
}
public boolean validName() {
boolean status;
String theName = name.getText();
Pattern pattern = Pattern.compile("[A-za-z0-9 ]+");
Matcher matcher = pattern.matcher(theName);
if (matcher.matches()) {
status = true;
}
else {
status = false;
}
return status;
}
}
COULD YOU EXPLAIN THESE SPECIFIC LINES HERE ONE BY ONE ?
/**
* #param o the object corresponding to the user's selection
*/
#Override
public void tell(Object o) { -- Where has this come from ?
deptCode.setText(o.toString());
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == submit) {
MyVerifier test = new MyVerifier();
if (Staff.getStaff(id.getText()) == null && test.verify(id) &&
test.verify(name)) {
System.out.println("YAY");-- What is this doing
}
else if (!(Staff.getStaff(id.getText()) == null)) {
String errorMessage = "ID EXISTS: " + Staff.getStaff(id.getText()).toString(); -- What is this doing
JOptionPane.showMessageDialog(theFrame, errorMessage, "Error",
JOptionPane.WARNING_MESSAGE);-- What is this doing
}
else {
System.out.println("Woops.");
}
}
else if (e.getSource() == clear) {
id.setText(null);
deptCode.setText(null);
name.setText(null);
}
}
public static void main(String[] args) {
Registration test = new Registration();
}
}
Now that you understand what you're trying to accomplish with this program, start from a clean slate (using your first attempt as an example if necessary). It's often easier to start over than to fix a program.
It appears that your public void tell(Object o) method is setting a String with the value of the object passed. Because you haven't shown us what your using it for, though, it's impossible for us to know for sure. On the other hand, your other problems are fairly clear:
System.out.println("YAY");
It appears that Staff.getStaff(id.getText) is checking either a String or a text file for a list of names and id's. This statement prints "YAY" only if there hasn't previously been created a staff member with the provided id and name. But since you also haven't shown us where those variables are, this is only my best guess.
JOptionPane.showMessageDialog(theFrame, errorMessage, "Error", JOptionPane.WARNING_MESSAGE);
This displays a JOptionPane warning message if there is already a staff member with the given id or name. Obviously, you cannot create an account that someone else has, so this JOptionPane displays an error message if this is, indeed, the case.

Java arraylist add the qty

I am having an issue with comparing the properties of myProduct.setRefno(product.getRefno()), imported from another class along with a description, price and qty. I need to be able to key in a refno and if the reference number exists in the basket container, then I add only the qty rather than all the item details:
Currently program works as follows:
ref1 description1 price1 1(qty)
ref2 description2 price2 1(qty)
ref1 description1 price1 1(qty)
However I would like it as:
ref1 description1 price1 2(qty)
ref2 description2 price2 1(qty)
If it is the same refno then it adds only the qty.
public class Zapper {
public static void main(String[] args) throws ItemException {
System.out.println("\n\nThis is Purchases\n\n");
Products stock=new Products();// Define Variable
Products basket=new Products();// Define Variable
Purchase product;
String refno;
int offer;
int count;
int grandtotal;
char option;//char variable option
boolean finished=false;//variable "boolean" set
while (!finished) {
try {
option=Console.askOption("\n A)dd P)rint R)emove Q)uit");
stock.open("stock.lin");
switch (option) {
case 'A':
product= new Purchase();
refno= Console.askString("Enter Ref No:..");
product=(Purchase)stock.find(refno);//cast operator
if ( product == null) {
System.out.println("Cannot find Ref No");
} else {
product.print("");
Purchase myProduct = new Purchase();
myProduct.setRefno(product.getRefno());
myProduct.setDescription(product.getDescription());
myProduct.setPrice(product.getPrice());
myProduct.setQty(1);
myProduct.setOffer(product.getOffer());
basket.add(myProduct);//add the value of item into Container stock
}
break;//end of case statement Add
case 'R':
refno= Console.askString("Enter Ref No:..");
Product myProduct = new Product();
myProduct=(Purchase)basket.find(refno);//cast operator
myProduct.setQty(1);
if ( myProduct == null)
System.out.println("Cannot find Ref No");
else {
basket.remove(myProduct);
basket.print("");
}
break;//end of case statement Find
case 'P':
basket.print("\nYou have purchased...");
break;//end of case statement Print
case 'Q':
finished=true;
break;//end of case statement "Q"
case '\0':/*Do Nothing*/
break;//end of case statement "Do Nothing"
default:
System.out.println("Error: Invalid Option ");
break;//end of case statement default
}
} catch (ItemException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
System.out.println("\n\nPurchases Finished \n\n");
}
}
You only have to change the add-method in your Products class. Supposing you store your Purchase-objects in a List in your Product class, it could look something like this:
private List<Purchase> products;
public void add(Purchase product) {
String refNo = product.getRefno();
for (Purchase p : this.products) { //for every product
if (p.getRefno().equals(refNo)) { //if two refNumbers equals
p.setQty(p.getQty() + product.getQty()); //add the desired quantity
return; //force method to abort
}
}
this.products.add(product); //otherwise, add the new product
}
Although, I have to say I find some of your class-namings a bit unusual. Remember they should always give a good hint on what they actually represent, eg your Purchase class looks more like a Product. :)
A lot of your problems will fall away if you use some proper OOP coding techniques.
Lets start with the structure of your class.
public class Zapper {
public static void main(String[] args) throws ItemException {
System.out.println("\n\nThis is Purchases\n\n");
Products stock=new Products();// Define Variable
Products basket=new Products();// Define Variable
Purchase product;
String refno;
int offer;
int count;
int grandtotal;
char option;//char variable option
//Do the work...
}
}
First of all, in no case should main throw an Exception, nevermind a particular one like ItemException. All such things should be handled gracefully by the program. Secondly, you instantiate a bunch of objects that really should be held as member fields within the class, Zapper.
This might be more in tune with what you want:
public class Zapper {
//These things will stay throughout the program
private Products stock = new Products();
private Products basket = new Products();
private Purchase product;
private boolean quitSignalReceived = false;
private Set<Option> options;//A list of keyboard inputs
public static void main(String[] args) {
System.out.println("\n\nInitiating Purchase of items\n\n"); //use a proper entrance message to your program
Zapper zapper = new Zapper();//Create an object! Sets up all class variables on construction.
zapper.run();//Let a method handle running the program.
System.out.println("\n\nPurchases Finished \n\n");//Say goodbye!
}
public void run() {
//actually does the work!
}
}
Now you just need to focus on what run() does. Specifically, it handles your 'main loop':
public void run() {
boolean finished = false;
stock.open("stock.lin"); //Should happen every time we enter the run() loop
while (!finished) {
option=Console.askOption("\n A)dd P)rint R)emove Q)uit");
processOption(option);
if (quitSignalReceived) {
//Do anything that MUST happen before the program quits.
finished = true;
}
}
}
You've astutely noticed at this point we need to add Options in and process them.
public Zapper() {
this.options.add(new AddOption());
this.options.add(new QuitOption());
//etc.
}
public class Option {
//Constructor, etc.
process(String option) {
for (Option o : options) {
if (o.getKey.equals(option)) {
o.process(this);
}
}
}
}
This will naturally require an abstract class, Option, that you subclass:
public abstract class Option {
public String getKey();//returns the keyboard key associated with this option
public void process(Zapper z); //actually does what you need the option to do.
}
Let us consider your 'A' case:
case 'A':
product= new Purchase();
refno= Console.askString("Enter Ref No:..");
product=(Purchase)stock.find(refno);//cast operator
if ( product == null) {
System.out.println("Cannot find Ref No");
} else {
product.print("");
Purchase myProduct = new Purchase();
myProduct.setRefno(product.getRefno());
myProduct.setDescription(product.getDescription());
myProduct.setPrice(product.getPrice());
myProduct.setQty(1);
myProduct.setOffer(product.getOffer());
basket.add(myProduct);//add the value of item into Container stock
}
break;//end of case statement Add
First of all, you new() your product, which instantiates an object. Two lines later you set the variable to another object altogether. Secondly, you get that object from a method that does not return a Purchase object, which you should avoid at all cost and at the least encapsulate against future change. Then you have an if switch against null - which is another practice you should always avoid.
In the case of adding a product you want the process method of your Option subclass to look like below.
public void process (Zapper zap) {
refno= Console.askString("Enter Ref No:..");
Purchase stockItem;
bool success = zap.getPurchase(refno, item);
if ( !success ) {
System.out.println("Item not in stock.");//Errors should make sense!
} else {
zap.addToBasket(stockItem);
}
}
This requires adding the following methods to Zapper:
public bool findPurchase(String refno, Purchase item) {
item = this.stock.find(refno);
if (item == null) { return false; }
}
public void addToBasket(Purchase item) {
//actually do the work to add it to your purchases.
}
And to Products:
//This method copies the object into a new object and returns it.
public Purchase getPurchaseItem() {
Purchase myProduct = new Purchase();
myProduct.setRefno(product.getRefno());
myProduct.setDescription(product.getDescription());
myProduct.setPrice(product.getPrice());
myProduct.setQty(1);
myProduct.setOffer(product.getOffer());
}
Now, note a tonne of work is done for you if you change this:
private Products stock = new Products();
private Products basket = new Products();
To this:
private Map stock = new HashMap();
private Map basket = new HashMap();
In this case your call to increment-or-add would look like this:
if (basket.containsKey(item)){
int quantity = basket.get(item) + 1;
basket.set(item, quantity);
} else {
basket.set(item, 1);
}
While this is long it touches on many of the ways you can clean up this code, put responsibility where it belongs and where it is easiest, and solve your problem. If the Map class is insufficent to your needs, you might consider a situation where you have an Item class that comprises an item in stock and a PurchasedItem class that extends that, which is the thing you buy. That's a whole other discussion.

Categories