How to exit all multiple nested methods at once - java

I've been following Tim Buchalka's course Java Programming Masterclass for Software Developers and I've been modifying his program from lesson 118.
I want to update my list at the runtime while using the list iterator (navigate method). The program runs fine, but if I update my list, Java throws an error: ConcurrentModificationException
I have come up with the following solution:
Whenever a user performs a modification of the list, other methods run, and update the list and pass it to the navigate() method. By doing this, my program enters multi-level nested methods, and the problem comes up when a user wants to exit from the program (case 0: in navigate() method). User has to press 0 as many times as many nested methods were ran.
My initial idea was to count how many times navigate() was nested, then using for loop return as many times as it was nested. But later I understood it does not make sense
What can I do to exit from the program by using case 0: just once?
package com.practice;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Scanner;
public class List extends Traveler {
private LinkedList<String> linkedList;
private String tripName;
public List(String travelerName, int travelerAge, String tripName) {//it has to have same amount of parameters or more with super constructor!
super(travelerName, travelerAge);
this.tripName = tripName;
this.linkedList = new LinkedList<>();
}
public List(){} //it has to have same amount of parameters or more with super constructor!
public LinkedList<String> getLinkedList() {
return linkedList;
}
public String getTripName() {
return tripName;
}
private void removeCity(LinkedList<String> cityList, String deletedCity) {
if(cityList.remove(deletedCity)) {
System.out.println(deletedCity + " has been removed");
} else System.out.println("Could not find the city you want to remove");
List.navigate(cityList);
}
//adds a new city and update the list without an error
private void noExceptionError(LinkedList<String> listOfCities, String cityName) {
ListIterator<String> listIterator = listOfCities.listIterator();
while((listIterator.hasNext())) {
int comparison = listIterator.next().compareTo(cityName);
if(comparison == 0) {
System.out.println(cityName + " has been already added to the list");
return;
} else if(comparison > 0) {
listIterator.previous();
break;
}
}
listIterator.add(cityName);
List.navigate(listOfCities);
}
private void loadToList(LinkedList<String> listOfCities) {
alphabeticallyAdd(listOfCities, "Poznan");
alphabeticallyAdd(listOfCities, "Gdansk");
alphabeticallyAdd(listOfCities, "Szczeczin");
alphabeticallyAdd(listOfCities, "Warszawa");
alphabeticallyAdd(listOfCities, "Lodz");
alphabeticallyAdd(listOfCities, "Wroclaw");
List.navigate(listOfCities);
}
private void alphabeticallyAdd(LinkedList<String> listOfCities, String cityName) {
ListIterator<String> listIterator = listOfCities.listIterator(); //just a setup; doesn't point to the 1st element
while((listIterator.hasNext())) {
//if value is greater, the word that is in the list is alphabetically bigger, thus, put it before the list element
//if equal, it is duplicate! return false
// else it is less, thus, we have to move further in the list
int comparison = listIterator.next().compareTo(cityName); //retrieves the 1st value and goes to the next
if(comparison == 0) {
System.out.println(cityName + " has been already added to the list");
return;
} else if(comparison > 0) {
listIterator.previous(); //because we've used .next() in the int comparison initialization
listIterator.add(cityName); //don't use linkedList.add because it doesn't know the int comparison, so cannot properly add!!!
return;
}
}
listIterator.add(cityName); //adding at the end of the list
}
public static void navigate(LinkedList<String> listOfCities) {
Scanner userChoice = new Scanner(System.in);
List travelListObject = new List();
ListIterator<String> listIterator = listOfCities.listIterator();
boolean goingForward = true;
while(true) {
Main.menu();
int choice = userChoice.nextInt();
userChoice.nextLine(); //takes care of enter key problem
switch(choice) {
case 0:
System.out.println("Goodbye");
//possible improvement
/* for(int i = 0; i <= List.amountNestedMethods; i++) {
return;
}*/
return;
case 1: //moving forward
if(!goingForward) {
if(listIterator.hasNext()) {
listIterator.next();
}
}
if(listIterator.hasNext()) {
System.out.println(listIterator.next());
Traveler.setNumberVisitedCities(Traveler.getNumberVisitedCities() + 1);
goingForward = true;
} else {
System.out.println("No more cities in the list");
goingForward = false;
}
break;
case 2: //moving back
if(goingForward) {
if(listIterator.hasPrevious()) {
listIterator.previous();
}
goingForward = false;
}
if(listIterator.hasPrevious()) {
Traveler.setNumberVisitedCities(Traveler.getNumberVisitedCities() + 1);
System.out.println(listIterator.previous());
} else {
System.out.println("You're at the beginning of the list");
goingForward = true;
}
break;
case 3:
Main.printCities(listOfCities);
break;
case 4:
break;
case 5:
System.out.println("Write new city");
String addedCity = userChoice.next();
travelListObject.noExceptionError(listOfCities, addedCity);
break;
case 6:
System.out.println("Write the city you want to delete");
String deletedCity = userChoice.next();
travelListObject.removeCity(listOfCities, deletedCity);
break;
case 7:
System.out.println("You have been in " + Traveler.getNumberVisitedCities() + " cities in total");
break;
case 9:
travelListObject.loadToList(listOfCities);
break;
default:
System.out.println("Something weird happened. Try to choose an option again");
}
}
}
}

If you want to exit the program you can simply call System.exit(n), where the n is an integer return code (the convention being that code 0 means normal execution and other values indicate some sort of error).

Related

Finding duplicates in an array of objects

The purpose of this project is to make a pokedex that adds and holds all the pokemon passed in by user input. When the user inputs a pokemon that is already stored in the pokedex the word "duplicate" is supposed to be printed to the console. The word duplicate is printed even though there are no actual duplicates within the object array. Here is my output from the console :
Welcome to your new PokeDex!
How many Pokemon are in your region?: 3
Your new Pokedex can hold 3 Pokemon. Let's start using it!
List Pokemon
Add Pokemon
Check a Pokemon's Stats
Sort Pokemon
Exit
What would you like to do? 2
Please enter the Pokemon's Species: red
Duplicate
Now here is all the code used that could possibly be making this error
import java.util.Scanner;
public class Project4 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Welcome to your new PokeDex!");
System.out.print("How many Pokemon are in your region?: ");
int size = input.nextInt();
Pokedex pokedex = new Pokedex(size);
System.out.println("\nYour new Pokedex can hold " + size + " Pokemon. Let's start using it!");
int choice = 0;
boolean done = false;
while (!done) {
System.out.println("\n1. List Pokemon\n2. Add Pokemon\n3. Check a Pokemon's Stats" + "\n4. Sort Pokemon\n5. Exit");
System.out.print("\nWhat would you like to do? ");
choice = input.nextInt();
switch (choice) {
case 1:
String[] pokemonList = pokedex.listPokemon();
if (pokemonList == null)
System.out.println("Empty");
else
for (int i = 0; i < pokemonList.length; i++) {
System.out.println((i + 1) + ". " + pokemonList[i]);
}
break;
case 2:
System.out.print("\nPlease enter the Pokemon's Species: ");
String species = input.next();
pokedex.addPokemon(species);
break;
}
}
}
}
In the following class I have the actual method that adds the pokemon and the constructor for Pokedex
public class Pokedex {
Pokemon[] pokedex;
String pokeArray[];
public Pokedex(int size) {
pokedex = new Pokemon[size];
pokeArray = new String[size];
}
public boolean addPokemon(String species) {
Pokemon stuff = new Pokemon(species);
for (int i = 0; i < pokedex.length; i++) {
if (pokedex[i] == null) {
pokedex[i] = stuff;
}
else if (i < pokedex.length && pokedex[i] != null) {
System.out.println("Max");
}
if (pokedex[i].getSpecies().equalsIgnoreCase(species)) {
System.out.print("Duplicate");
break;
}
}
return false;
}
}
Sorry for the mass amounts of code I just need help tracing where this unexpected result is coming from.
The reason it's doing that is because of this bit of code here:
public boolean addPokemon(String species)
{
Pokemon stuff = new Pokemon(species);
for (int i = 0; i < pokedex.length; i++)
{
if (pokedex[i] == null)
pokedex[i] = stuff;
else if (i < pokedex.length && pokedex[i] !=null)
System.out.println("Max");
if(pokedex[i].getSpecies().equalsIgnoreCase(species))
{
System.out.print("Duplicate");
break;
}
}
return false;
}
The problem is just a little bit of syntax missing. In your for loop, you check to see if
A) there are any empty spots in the array
B) if every element in the array up to the user inputted size is full
and C) if any element in the array matches the one we're trying to add.
The problem you're encountering is because your C is an if instead of an else if. Because A sees the index is null, it assigns the new Pokemon to the Pokedex. Then because C is an if instead of an else if, it runs after you assign the new Pokemon and sees the Pokemon we just added and says it's a duplicate. Changing it to an else if would fix this.
Also, since there was no break; in A, it would assign every element of the array to the first one entered, causing any further additions to call Max. I edited the code and this is what I had that worked for me:
public boolean addPokemon(String species)
{
Pokemon stuff = new Pokemon(species);
for (int i = 0; i < pokedex.length; i++)
{
if(pokedex[i] !=null && pokedex[i].getSpecies().equalsIgnoreCase(species))
{
System.out.println("Duplicate");
break;
}
else if (pokedex[i] == null)
{
pokedex[i] = stuff;
break;
}
else if(i + 1 == pokedex.length)
{
System.out.println("Max");
break;
}
}
return false;
}
Also, out of curiosity, why is the addPokemon() function a boolean? You return a value (albeit arbitrarily) and then never do anything with that value. You could just make it a void, have it return nothing, and it would work just as fine.

Removing position from HashMap

I'm working on a something like music player. I'm building playlist on HashMap, I have a problem with deleting specific setlist(case 5). It works but when I delete position in the middle of the list case 1 (showing all playlists) no longer works because I have empty space (1,2,3,deleted,5,6....). Now how do I make those positions after deleted one decrease index by one? Looks like x-- doesn't solve my problem. I hope you understand my problem, here is the code, if you need me to translate anything to English just ask. Thanks for help!
package PLAYLIST2;
import java.util.HashMap;
import java.util.Scanner;
public class Odtwarzacz {
// String lista;
// Odtwarzacz(Playlist) {
// lista = b;
// }
public static void main(String[] args) {
int nr;
int koniec = 0;
String nazwa11;
int x = 0;
HashMap<Integer, Playlist> Playlista = new HashMap<Integer, Playlist>();
Playlista.put(x, new Playlist("Rock"));
x++;
Playlista.get(0).dodajUtwor("Stockholm Syndrome", "Muse", 2004);
Playlista.get(0).dodajUtwor("Absolution", "Muse", 2004);
Playlista.put(x, new Playlist("Pop"));
x++;
Scanner odczyt = new Scanner(System.in);
// TODO Auto-generated method stub
while (koniec == 0) {
System.out.println("_________________________");
System.out.println("1.Wyświetl listę playlist");
System.out.println("2.Dodaj playlistę");
System.out.println("3.Wyświetl playlistę");
System.out.println("4.Posortuj playlistę");
System.out.println("5.Usuń playlistę");
nr = odczyt.nextInt();
switch (nr) {
case 1: {
System.out.println("Lista playlist: ");
for (int i = 0; i < x; i++) {
System.out.println(i + ". " + Playlista.get(i).Nazwa());
}
break;
}
case 2: {
System.out.print("Podaj nazwę nowej playlisty: ");
nazwa11 = odczyt.next();
Playlista.put(x, new Playlist(nazwa11));
System.out.println("Dodano playlistę: "
+ Playlista.get(x).Nazwa());
x++;
break;
}
case 3: {
System.out.print("Podaj numer playlisty:");
nr = odczyt.nextInt();
Playlista.get(nr).wyswietlListe();
break;
}
case 4: {
System.out.print("Podaj numer playlisty:");
nr = odczyt.nextInt();
Playlista.get(nr).sortuj();
break;
}
case 5: {
System.out.print("Podaj numer playlisty:");
nr = odczyt.nextInt();
System.out.println("Skasowano playlistę: "
+ Playlista.get(nr).Nazwa());
Playlista.remove(nr);
x--;
break;
}
}
}
}
}
You do not seem to need a HashMap.
A HashMap is just a key-value store that has no order.
In your case, a List seems like a better choice. It comes with an order since it is the main point of it.
You can specifically use a ArrayList:
List<Playlist> playlists = new ArrayList<>();
playlists.add(new Playlist("Rock"));
// ...
Playlist p = playlists.get(index);
If you want to safely remove and get correct keys after, you must iterate the Map
int count = 0;
boolean found = false;
Iterator<Map.Entry<Integer,String>> iter = TestMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<Integer,String> entry = iter.next();
if("Sample".equalsIgnoreCase(entry.getValue())){
iter.remove();
found = true;
}
if (found) {
// set the new key using count...
}
count ++;
}
first let me see if i understand your problem correctly or not . you like to reoder playlist after any delete operation. 1,2,3,4,5 . you delete 3 , then it should be 1,2,4,5 and not 1,2, ,4,5.
if above is true , best is use linkedhashmap collection. also case1 you can rewrite as
case 1: {
System.out.println("Lista playlist: ");
for (Playlist pll:Playlista.values()) {
System.out.println(i + ". " + pll.Nazwa());
}
break;
}

Why this following Iterator turning into an infinite loop even thought it has a return statement in it?

Here is the method that I wrote that turns into an infinite loop printing "Same Pinch...!!!" endlessly: (right after the print statement, I have a return statement which should end the method after printing "Same Pinch...!!!" one time.
public boolean contains(Object input) {
if(input == null){
throw new IllegalArgumentException();
}
AIterator<R> myAsetIterator = (AIterator<R>) this.iterator();
//use checkType(o) here in if statement and work from there please
while(myAsetIterator.hasNext()) {
indexToRemove++;
if(input.equals(myAsetIterator.next())) {
System.out.println("Same Pinch...!!!");
return true;
}
}
return false;
}
Here is it's tester method. It's just a part of the main method.
private void testConstruction() {
System.out.println("\nTesting Constructor");
System.out.print("----------------------------------------");
System.out.println("----------------------------------------");
ArrayList<String> temp = new ArrayList<String>();
temp.add("Butterfinger");
temp.add("Milky Way");
temp.add("Kit Kat");
temp.add("Three Muskateers");
temp.add("Three Muskateers");
Aset s3 = new Aset(temp);
test(s3.getCapacity() == 10,
"new Aset(temp) should return a capacity of 10: " + s3.getCapacity());
test(s3.size() == 4,
"size should return 4: " + s3.size());
test(s3.toString().equals("<Butterfinger, Milky Way, Kit Kat, Three Muskateers>"),
"toString should return\n "+
"\"<Butterfinger, Milky Way, Kit Kat, Three Muskateers>\":\n "
+ s3.toString());
}

Removing a node from a linked list by specifying one parameter of the objects stored

I hope my question doesn't bore you. I have been tasked to create a menu and a voting system, I am trying to dynamically add candidates onto a linked list, with the name and the party of the candidate being the only parameters. In the menu I have the option to delete a candidate if the user wishes to do so, so he is prompted to enter the name of the candidate, supposedly unique, and then the node containing that object should be removed. This what I have so far:
package votingEntities;
import java.util.*;
public class CandidateMakerMenu
{
#SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args)
{
int menuChoice = 0;
//int numOfCandidates = 0;
int candidates = 0;
String nameOfCandidate;
String partyOfCandidate;
LinkedList candidateList = new LinkedList();
do
{
System.out.println("Please Choose an Option:\n");
System.out.println("\t1. Add Candidate\n"
+ "\t2. List Candidates\n"
+ "\t3. Delete Candidate\n"
+ "\t4. Vote\n"
+ "\t5. Results\n"
+ "\t6. New Election\n"
+ "\t7. Exit\n");
menuChoice = EasyIn.getInt();
switch (menuChoice)
{
case 1:
System.out.println("\nName of candidate "+(candidates+1)+" : ");
nameOfCandidate = EasyIn.getString();
if(candidateList.indexOf(nameOfCandidate) != -1)
{
System.out.println("\nCandidate name has to be unique, please choose different name\n");
break;
}
System.out.println("\nParty of candidate "+(candidates+1)+" : ");
partyOfCandidate = EasyIn.getString();
Candidate c = new Candidate(nameOfCandidate,partyOfCandidate);
candidateList.add(c);
candidates++;
System.out.println("\nNumber of Candidates: "+candidates);
break;
case 2:
if(candidates < 1)
{
System.out.println("\nNo candidates in list yet\n");
break;
}
System.out.println(candidateList);
break;
case 3:
if(candidates < 1)
{
System.out.println("\nNo candidates to delete\n");
break;
}
System.out.println("\nEnter name of candidate to delete: ");
nameOfCandidate = EasyIn.getString();
int candidateIndex =candidateList.indexOf(nameOfCandidate);
if(candidateIndex == -1)
{
System.out.println("\nCandidate can not be found in list\n");
break;
}
else
{
candidateList.remove(candidateIndex);
candidates--;
}
case 4:
break;
case 5:
break;
case 6:
candidateList.clear();
break;
case 7:
System.exit(0);
default:
System.out.println("\nChoice must be a value between 1 and 6.\n");
}
}
while(menuChoice != 7);
}
So my issue is with case 3, I don't understand why is it not removing the object. I'm new to implementing linked lists, so I understand it might be something silly but I would appreciate any hints.
If it make sense, you could define equality on Candidate class to return true if name is same :
class Candidate {
String name; // or whatever is is really is your class
String party; // same as abover
...
public boolean equals(Object other) {
if (! (other instanceof Candidate)) {
return false;
}
return name.equals(((Candidate) other).name);
}
public int hash() {
return name.hash();
}
}
That way, you can successfully use indexOf on the list of Candidate to find nameOfCandidate :
Candidate c = new Candidate(nameOfCandidate, "anyPartyName");
int candidateIndex =candidateList.indexOf(c);
You are trying to remove using candidate name. String is also an object. So you are comparing String object with Candidate object if you used generic Linked List it will throw a compile time error so use generic linked list
LinkedList<Candidate> candidateList = new LinkedList<Candidate>();
use iterator to remove object.
for(Iterator<Candidate> iter = list.iterator(); iter.hasNext();) {
Candidate data = iter.next();
if (data.name.equalIgnoreCase(nameOfCandidate) {
iter.remove();
}
}
Thank you everyone, #Exbury I used your method and it works perfectly
case 3:
if(candidates < 1)
{
System.out.println("\nNo candidates to delete\n");
break;
}
System.out.println("\nEnter name of candidate to delete: ");
nameOfCandidate = EasyIn.getString();
Candidate cToDelete = new Candidate(nameOfCandidate, "anyPartyName");
int candidateIndex =candidateList.indexOf(cToDelete);
if(candidateIndex == -1)
{
System.out.println("\nCandidate can not be found in list\n");
break;
}
else
{
candidateList.remove(candidateIndex);
candidates--;
}

using switch block in java instead of multiple if statements

public class A {
public void search(boolean[] searchList) {
// searchList array is used to identify what options to search for in a given order
// e.g. boolean [] searchList = new boolean [] {false, false, true, false};
boolean searchL = false;
boolean searchM = false;
boolean searchK = false;
boolean searchA = false;
if(searchList[0] == true) searchL = true;
if(searchList[1] == true) searchM = true;
if(searchList[2] == true) searchK = true;
if(searchList[3] == true) searchA = true;
if(searchL == true) // write a query to search for all Ls
if(searchM == true) // write a query to search for all Ms
...........
}
Is there a way I can simplify this code ?
#All : Sorry for posting a wrong question before. I was confused!
Thanks,
Sony
I am a big fan of enums:
public class A {
enum SearchType {
L, M, A, K;
}
public void search(SearchType type) {
switch (type) {
case L:
System.out.println("Searching for L");
break;
case M:
System.out.println("Searching for M");
break;
case A:
System.out.println("Searching for A");
break;
case K:
System.out.println("Searching for K");
break;
default:
System.out.println("what to do here?");
// throw exception?
}
note also: your scenario allowed more than one search boolean to be true at a time, I assumed that was not your goal, but if it is we can tweak this a bit.
You should convert your state into an enum. For example your search booleans seem to be exclusive so i would do something like this:
enum SearchOption {
searchA, searchK, searchL, searchM
}
// then you can do
SearchOption searchOption = searchA;
switch (searchOption) {
case searchA:
System.out.println("I am searching for A");
break;
case searchK:
System.out.println("I am searching for K");
break;
case searchL:
System.out.println("I am searching for L");
break;
case searchM:
System.out.println("I am searching for M");
break;
}
If your states aren't exclusive you should try build to build a super set of exclusive states initially.
Why don't employ OOP? Like:
public interface Seeker {
void seek();
}
public class LSeeker implements Seeker {
void seek() { System.out.println("Will search for L"); }
}
// ... More implementations of Seeker
public class SeekDriver {
void seek(Seeker seeker) { seeker.seek(); }
}
public class A {
public enum SearchOption {
SEARCH_L,
SEARCH_M,
SEARCH_A,
SEARCH_K;
}
/**
* Make them pass in an enum for your search.
* Pros: type safe, can only use the selections you give
* Cons: must add to the enum to add new types
* #param option
*/
public void enumSearch(SearchOption option) {
switch(option) {
case SEARCH_A:
System.out.println("I am searching for A");
break;
case SEARCH_K:
System.out.println("I am searching for K");
break;
case SEARCH_L:
System.out.println("I am searching for L");
break;
case SEARCH_M:
System.out.println("I am searching for M");
break;
}
}
/**
* Use a primitive for your input
* Pros: Gives you more options without updating the enum
* Cons: Users could enter input you don't really want them to use
* #param option
*/
public void charSearch(char option) {
switch(option) {
case 'a':
case 'A':
System.out.println("I am searching for A");
break;
case 'k':
case 'K':
System.out.println("I am searching for K");
break;
case 'l':
case 'L':
System.out.println("I am searching for L");
break;
case 'm':
case 'M':
System.out.println("I am searching for M");
break;
}
}
/**
* Use a primitive and don't even actually check it! Just run with it!
* #param option
*/
public void uncheckedSearch(char option) {
System.out.println("I am searching for " + option);
}
}
As per your comment, here's my updated example of that method - make sure the comment at the top is updated!
/**
* Perform the search based on the options provided
* The list should be in the order of L, M, A, K
* #note update this comment as more search options are added
* #param searchList the list of flags indicating what to search for
*/
public void search(boolean[] searchList) {
// as per docs, [0] denotes an L search:
if(searchList[0])
// write a query to search for all Ls
// as per docs, [1] denotes an M search:
if(searchList[1])
// write a query to search for all Ms
// as per docs, [2] denotes an A search:
if(searchList[2])
// write a query to search for all As
// as per docs, [3] denotes a K search:
if(searchList[3])
// write a query to search for all Ks
}
Latest idea:
// Use the SearchOption enum from above
Map<SearchOption, String> searches = new HashMap<SearchOption, String>();
public List<SearchResult> search(List<SearchOption> options) {
List<SearchResult> results = new LinkedList<SearchResult>();
for(SearchOption option : options) {
String query = searches.get(option);
SearchResult result = MySearchService.executeQuery(query);
results.add(result);
}
return results;
}
Like this: ?
public class A {
public void search() {
private static final int SEARCH_L = -1;
private static final int SEARCH_M = 0;
private static final int SEARCH_A = 1;
private static final int SEARCH_K = 2;
int status;
switch(status){
case SEARCH_L:
System.out.println("I am searching for L");
break;
case SEARCH_M:
System.out.println("I am searching for M");
break;
// Etc
default:
// Log error didn't hit a known status
break;
}
}

Categories

Resources