Why doesn't my string change? - java

public static void read(String a[], double b[], String c) throws IOException {
Scanner in = new Scanner(new File("data.txt"));
while (in.hasNext()) {
int i = 0;
String id = in.next();
String name = in.next();
String lastname = in.next();
double grade = in.nextDouble();
if (name.substring(0, 2).equalsIgnoreCase(c)) {
a[i] = id + "\t" + name + "\t" + lastname + "\t" + grade;
b[i] = grade;
}
i++;
}
}
When I use this method with
String men[] = new String[501];
double menGrade[] = new double[501];
read(men, menGrade, "MR");
My men[0] is assigned a String but men[1] to men [500] are all null ...

You need to declare your variable i outside of the while loop to keep it incremented.
Right now you are
declaring it with value 0
assign the values to the 1st array position
increment i, and then
declare it again with value 0 at the next loop iteration.
SO, just change your lines:
while (in.hasNext()) {
int i = 0;
to
int i = 0;
while (in.hasNext()) {
Your code has also other issues which you should adress in some way.
I do not know why you initialize your array with a fixed size of 500 and also check some conditions before you add your men and grades to those Arrays. This will however lead to a few problems if you are not careful.
Right now you would have holes in your array whenever the if condition does not evaluate to true.
Also your program would crash if there is more than 500 entries in your file.
A rather good solution when dealing with dynamic data structures (so, when you do not know beforehand how many records you will have exactly), is to use a dynamic data structure.
In java you can have a look at java.util.List interface and probably java.util.ArrayList as a good implementation.
Here is also the java doc of that class: Java Doc
Here you find more on the collections api which are a good thing for dynamic data structures: Collections - List tutorial

while (in.hasNext()) {
int i = 0;
...
This will RESET i each time you start the while loop and you always overwrite a[0] and b[0].
swap these two lines! (so the int i = 0; comes before the loop:
int i = 0;
while (in.hasNext()) {
...

You should increment i in your if statement and not always like you do now. You don't want holes in your men array.

This simply means, either your loop is executing only once.
Or, if block in loop is exceuting only once.
Dependecy is on the content of file you are importing and your if condition.

I'm pretty sure that something is wrong with your "data.txt" that caused the while loop to execute only once. Otherwise, I don't see any mistake in the code.
Why don't you check the value of i during the execution of the program?

If your data.txt file contains One single line then the corresponding while will be running for once populating the first element of the array i.e men in your case

The reason is this:
while (in.hasNext()) {
int i = 0;
...
i++;
}
you are destroying and creating i variable each time loop is executed effectively reseting it to 0 each time. Asides from notes from other answers you can simply move i outside the loop:
int i = 0;
while (in.hasNext()) {
...
i++;
}

Now I can't run in myself, but I see
while (in.hasNext()) {
int i = 0;
//other
a[i] = id + "\t" + name + "\t" + lastname + "\t" + grade;
b[i] = grade;
}
i++;
If you use a counter i over an array/Collection, generally you have to give a greater scope to counter.
if the counter is inside the while, at every iteration you recreate the counter and you point always at the same element of array
The/one solution can be:
int i=0;
while (in.hasNext()) {
//etc

Related

how to print Scanner element using parallel arrays in java?

I am new to learning about parallel arrays and want to know how to effectively print content/elements using parallel array only, I tried but couldn't get it to work and function the way I want.
The task is: The program inputs an integer from the user representing how many peoples’ information will be entered. Then, the program inputs the information one person at a time (name first, then age), storing this information in two related arrays.
Next, the program inputs an integer representing the person on the list whose information should be displayed (to get information for the first person, the user would enter ‘1’). The program makes a statement about the person’s name and age.
Although I got the name and age to work until the integer the user inputs, but after that I am not sure how to do
Sample input:
4
Vince
5
Alexina
8
Ahmed
4
Jorge
2
2 // I am confused about this part, how would I make it so that it prints the desired name,
//for example with this input, it should print:
Sample output:
Alexina is 8 years old
My code:
import java.util.Scanner;
class Example {
public static void main (String[] args) {
Scanner keyboard = new Scanner(System.in);
int[] numbers = new int[keyboard.nextInt()];
for (int x = 0; x < num.length; x++){
String[] name = {keyboard.next()};
int[] age = {keyboard.nextInt()};
}
int num2 = keyboard.nextInt();
System.out.println(); // what would I say here?
}
}
You need to rewrite your code so your arrays aren't being assigned within the loop. You want to add values to the arrays, not reset them each time, and you want to be able to access them afterwards. Below is a modified version of your code:
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int num = keyboard.nextInt();
keyboard.nextLine(); //you also need to consume the newline character(s)
String[] name = new String[num]; //declare the arrays outside the loop
int[] age = new int[num];
for (int x = 0; x < num; x++){
name[x] = keyboard.nextLine(); //add a value instead of resetting the array
age[x] = keyboard.nextInt();
keyboard.nextLine(); //again, consume the newline character(s) every time you call nextInt()
}
int num2 = keyboard.nextInt() - 1; //subtract one (array indices start at 0)
System.out.println(name[num2] + " is " + age[num2] + " years old"); //construct your string with your now-visible arrays
}
As I think you have to think about the local and global variable usage in java.In brief,
Local variables can only use within the method or block, Local variable is available only to method or block in which it is declared.
For example:
{
int y[]=new Int[4];
}
this y array can be accessed within the block only.
Global Variable has to be declared anywhere in the class body but not inside any method or block. If a variable is declared as global, it can be used anywhere in the class.
In your code you try to create arrays and use them out of the For loop. But your arrays are valid only inside the For loop. After every loop runs all info is lost.there will be new array creation for every iteration of For loop.
therefore, In order to access and save the information you have to declare your arrays before the For loop and access and store data using iteration number as the index. finally, to print the data you gathered, you have to scan new input as integer variable.then you can access your arrays as you wanted.
//For example
int [] age=new int[4]; //global -Can access inside or outside the For loop
int[] numbers = new int[keyboard.nextInt()];
for (int x = 0; x < 4; x++){
age[x] = keyboard.nextInt(); //Local
}
int num2 = keyboard.nextInt();
System.out.println(age[num2]); // Here you have to access global arrays using num2 num2
}
}

Get Data by Given Index

While coding a program for employee-management, I need a method which spits out the corresponding data to a specific index (the number given by the user).
Already tried a lot of methods to make this happen, for example the one below, with no success:
public static void ausgabeIndex(int index, String[] nN, String[] vN, String[] adres) {
Scanner sc = new Scanner(System.in);
System.out.println("Please insert the number of the registered employees: ");
index = sc.nextInt();
for (int i = 0; i < nN.length; i++) {
if (nN[i].equals(index)) {
System.out.println(nN[index]);
System.out.println(vN[index]);
System.out.println(adres[index]);
}
}
}
It's unclear if there is more than one issue here, since you didn't say what the actual problem was, other than it doesn't work.
Also, your data here is a bit strange. This would be better suited as a class to encapsulate all the data instead of three string arrays.
I suspect, however, that this is part of your problem: nN[i].equals(index)
nN is an array of String, and index is an int. These will never be equal. They aren't the same data type.
To properly compare a String and an integer, you need to either convert the String to an int or the int to a String. Converting an int to a String is the safer option, so you could do this:
nN[i].equals(String.valueOf(index))
To do the opposite, converting a String to an int, you can use Integer.parseInt(String)
Integer.parseInt(nN[i]) == index
One more note:
public static void ausgabeIndex(int index
You are passing in index but immediately overwriting it with your Scanner.nextInt. You don't need it as a method argument.
You need to address the following things in your code:
Whenver you try to access an element from an array, make sure you check the bounds to avoid ArrayIndexOutOfBoundsException e.g. you have accessed vN[index] without checking whether index is less than vN.length. adres[index] also has the same problem.
nN[i] is a String while i is an int and therefore they can not be compared unless you change the one into the other. However, I'm sure you didn't mean to compare nN[i] with index. Looking at your program, it seems you want to compare nN[i] with nN[index].
Since you are already passing index as a parameter to the method, the following lines do not make sense unless you want to override the value of index. If you do not want to override the value of parameter, index, remove these lines.
Scanner sc = new Scanner(System.in);
System.out.println("Geben Sie bitte die Nummer des/der regestrierten Mitarbeiters/Mitarbeiterin ein: ");
index = sc.nextInt();
Alternatively, if you want to keep these lines in the method, remove the parameter, index. As I've mentioned above, keeping both of these makes sense only if you want to override the value of parameter, index.
Given below is the code incorporating these comments:
public static void ausgabeIndex(int index, String[] nN, String[] vN, String[] adres) {
if(index < nN.length) {
for (int i = 0; i < nN.length; i++) {
if (nN[i].equals(nN[index])) {
System.out.println(nN[index]);
if (index < vN.length) {
System.out.println(vN[index]);
}
if (index < adres.length) {
System.out.println(adres[index]);
}
}
}
} else {
System.out.printnl("The index, " + index + " is out of the bounds.");
}
}

Using scanner with xml

I have,
1. I have an xml file consists of individuals info.
2. Hash map that reads the xml-file.
3. Scanner that lets the user gives an individual name(just the name), so that code compare with the information stored in the has map if i matches ant then then the code prints that individual information(name, phone etc).
I face an issue with the looping part, can you help to get to work ?
From my Main class:
System.out.println("Please enter a name:");
Scanner scan = new Scanner(System.in);
Person c1 = new Person();
c1.setName(scan.nextLine());
String value = c1.getName();
c1.getTimeInfo(value);
From my Person class:
public void getPersonInfo(String value)
{
List<Person> t = persons.get(name);
int iD ;
value = t.get(0);
for(int i = 0; i < t.length(); ++i) {
if(t.get(i) == value) {
value = t.get(i);
this.iD = i;
}
System.out.println("The person info : " + this.name.get(iD) + "-" +this.phone.get(iD) + " "+ this.address.get(iD)+ "-" + this.title,get(iD));
The way your getPersonInfo() method functions now is to return the last person in the names list. This is because you reassign the input value to t.get(0), and then loop through the list. This will result in the last name always being returned. You can do without having a variable for this comparison, as you don't use it in your output. Also, you should never use == for comparing strings, use .equals() instead, like so:
public void getPersonInfo(String value){
List<Person> t = persons.get(name);
int iD ;
for(int i = 0; i < t.length(); ++i) {
if(t.get(i).equals(value)) {
this.iD = i;
}
System.out.println("The person info : " + this.name.get(iD) + "-" +this.phone.get(iD)
}
}
This still does not prevent nothing from happening if the input value is not in the name list, so you may want to take care of that case. However, this will prevent you from always printing the information about the last person in the names list.
Also, you are comparing a Person to a string in the if- statement in the for loop, so either change the input to a Person or the list of people to a list of strings.

Why is method not working as I thought it would?

I am attempting to create a hangman game. I have everything working as I want so far with the exception of one method. This method is called processGuess and takes a String letter and two String arrays as parameters. The first array is an array called spaceArray and contains Underscores that match the length of the word being guessed (example: hello produces [ _ , _ , _ , _ , _ ]). The second array is called wordArray and contains the word the user is trying to guess.
The way I envision my method working is as follows:
Create an array that stores all guessed letters (guessArray)
Create a counter that keeps track of the number of guesses (guessCounter)
Use a for loop to iterate through each letter of the word and compare it with the letter the user guessed.
a. If the letter is in the word, add the letter to the correct index of the spaceArray
Compare spaceArray to wordArray
a. If equal, print something saying they won in x number of guesses
b. If not equal.
Print spaceArray
Call the method that asks user to guess the next letter
Call this method so that the new guessed letter is processed.
The problem is that when I recall this method, it does not contain the new letter but still contains the old letter. I am unsure of what I am doing wrong. This is the first time that I have tried using methods within a method.
Here is my method:
public static void main(String[] args) throws FileNotFoundException {
Scanner file = new Scanner(
new File("C:/FilesForJava/ScrabbleDictionary.txt"));
instructions();
String[] dictionary = createDictonaryArray(file);
String[] randomWord = getRandomWord(dictionary);
String[] underscoreArray = showSpaces(randomWord);
String letter = getGuesses();
processGuess(letter, underscoreArray, randomWord);
}
public static void instructions() {
System.out.println("Let's play hangman!");
System.out.println();
}
public static String[] createDictonaryArray(Scanner inputFile)
throws FileNotFoundException {
int wordCount = 0;
while(inputFile.hasNext()) {
String word = inputFile.next();
wordCount++;
}
String[] scrabbleDictionary = new String[wordCount];
Scanner file = new Scanner(
new File("C:/FilesForJava/ScrabbleDictionary.txt"));
while(file.hasNext()) {
for(int i = 0; i < wordCount; i++) {
scrabbleDictionary[i] = file.next();
}
}
file.close();
return scrabbleDictionary;
}
public static String[] getRandomWord(String[] dict) {
String word = dict[(int)(Math.random() * dict.length)];
String[] wordArray = new String[word.length()];
for(int i = 0; i < wordArray.length; i++) {
wordArray[i] = word.trim().substring(0, 1);
word = word.trim().substring(1);
}
return wordArray;
}
public static String[] showSpaces(String[] word) {
String[] spaceArray = new String[word.length];
for(int i = 0; i < word.length; i++) {
spaceArray[i] = "_";
}
System.out.println(Arrays.toString(spaceArray));
System.out.println();
return spaceArray;
}
public static String getGuesses() {
Scanner guess = new Scanner(System.in);
System.out.println("Guess a letter: ");
String letter = guess.next();
System.out.println();
//guess.close();
return letter;
}
public static void processGuess(String letter, String[] spaceArray,
String[] wordArray) {
int guessCounter = 0;
String[] guessArray = new String[spaceArray.length];
for(int i = 0; i < spaceArray.length; i++) {
guessCounter++;
guessArray[i] = letter;
String indexLetter = wordArray[i];
if(indexLetter.equalsIgnoreCase(letter)) {
spaceArray[i] = letter;
}
}
if(spaceArray.equals(wordArray)) {
System.out.println("Yes! You won in " + guessCounter + "guesses!");
}else {
System.out.println(Arrays.toString(spaceArray));
getGuesses();
processGuess(letter, spaceArray, wordArray);
}
}
You need to pass the new guess into your processGuess method. Try something like this:
else {
System.out.println(Arrays.toString(spaceArray));
String newLetter = getGuesses();
processGuess(newLetter, spaceArray, wordArray);
}
I think this method is trying to do too much. It's strange for it to read new input and call itself recursively -- I would have expected its caller to use a loop to solicit guesses from the player and call this method (which would not recurse) instead. The method might indicate by a return value whether the user had won.
Additionally, the code seems overly complex. For instance, what's the point of guessArray, which you instantiate and initialize but never use for anything?
Furthermore, it's strange that you use arrays of Strings instead of arrays of chars, since all your Strings seem to contain a single character each. (That might actually be appropriate if you are looking to accommodate surrogate pairs, but such a consideration seems a little out of character for the level of the task.)
In any event, the reason the recursive calls to your method see only the first letter guessed is that that's what you pass to them. The getGuesses() method does nothing to modify the local letter variable (nor can it do), and the method itself just passes along whatever was passed to it.
Well, it looks like you might have a couple of problems.
First, recursion is a very poor choice for this method, I think what you're looking for is a while loop where the condition changes when the strings are equal. Using recursion here needlessly increases the size of the stack as you call more and more methods, but never return from them.
Now as to your question, in the code you gave us, the variable letter never gets changed. I assume that get guesses returns a string? If thats true then you need to set letter equal to it.
I would also like to suggest that you use a char instead of a string.
public static void processGuess(String letter, String[] spaceArray,
String[] wordArray) {
while(true) {
int guessCounter = 0;
String[] guessArray = new String[spaceArray.length];
for (int i = 0; i < spaceArray.length; i++) {
guessCounter++;
guessArray[i] = letter;
String indexLetter = wordArray[i];
if (indexLetter.equalsIgnoreCase(letter)) {
spaceArray[i] = letter;
}
}
if (spaceArray.equals(wordArray)) {
System.out.println("Yes! You won in " + guessCounter + "guesses!");
break;
} else {
System.out.println(Arrays.toString(spaceArray));
letter = getGuesses();
}
}
}
You've written the method as a recursive method (probably not the best way to do it). The issue is that when a recursive method declares a local variable, each invocation of the recursive method has its own copy of the local variables.
Thus you call processGuess, which creates a guessArray. Then processGuess calls itself again, which has its own guessArray, and after this happens a few times, you'll have a stack that looks something like:
+--------------------------------------------------------+
+ processGuess#1 +
+ local variables: guessCounter#1, guessArray#1, i#1 +
+--------------------------------------------------------+ --> calls:
+ processGuess#2 +
+ local variables: guessCounter#2, guessArray#2, i#2 +
+--------------------------------------------------------+ --> which calls:
+ processGuess#3 +
+ local variables: guessCounter#3, guessArray#3, i#3 +
+--------------------------------------------------------+ --> which calls:
+ processGuess#4 +
+ local variables: guessCounter#4, guessArray#4, i#4 +
+--------------------------------------------------------+
When processGuess#4 modifies guessArray, it changes guessArray#4. But that has no effect on guessArray#3, guessArray#2, or guessArray#1. All of these are separate local variables, and they are references that refer to four different objects. Thus, when processGuess#4, processGuess#3, and processGuess#2 all return, the changes they've made to their own guessArray's are lost, and processGuess#1 will see only the changes that it, itself, has made to its own guessArray.
As I said, I wouldn't use recursion for this particular problem. But it's definitely a problem in other cases where recursion is the right way to do things. The solutions are: (1) declare the variable or object outside the recursive method, as an instance field in the object--then they will all be accessing the same variable; or (2) add a parameter to the recursive method so that the recursive invocations can share a reference to the same object.
[Note: The #1, #2 numbers I added are just to help explain things; they aren't part of any language syntax or anything like that.]

Why is this loop bad practice? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
The following loop is not good practice. Is it due to a String being the main condition of the for loop rather than an int variable, meaning the for loop is infinite? Also, is it due to there being no instance to enter 'end' to stop the loop?
Scanner in = new Scanner(System.in);
int i = 0;
for (String s = in.next(); !s.equals("end"); i++)
{
System.out.println("The value of i is: " + i + " and you entered " + s);
}
How can I rewrite it, so that it conforms to accepted style?
(This is a question in a past exam paper.)
Well your string s is never changing, which can lead to an infinite loop. You probably wanted:
for (String s = in.next(); !s.equals("end"); s = in.next(), i++) {
...
}
Some (me included) might say that i++ shouldn't be in the increment section of this loop, since it's not directly relevant to the condition:
for (String s = in.next(); !s.equals("end"); s = in.next()) {
...
i++;
}
Is it due to a string being the main condition of the for loop rather than an int variable, meaning the for loop is infinite?
The original loop was indeed infinite (at least, after an initial input is entered and assuming "end" wasn't the first input). However, it's not for the reason you state. For-loops are most commonly written using integral loop control variables, but it's not always the case. For example, a common idiom for iterating through a linked list is:
for (Node node = list.head; node != null; node = node.next) {
...
}
The problem with your loop is that the string s is never changed, so it will never equal "end" unless that's the first input.
I would suggest separating the looping condition and the call to Scannner.next():
while (in.hasNext()) {
String s = in.next();
if (s.equals("end")) {
break;
}
System.out.println("The value of i is: " + i + " and you entered " + s);
i++;
}
I think this is much easier to understand than trying to squeeze everything into a for expression.
There are multiple problems with this code:
s never changes after the initial assignment, so it's an infinite loop.
Calling .next() could throw NoSuchElementException or IllegalStateException. Rather than catching these exceptions, I consider it more polite to check .hasNext() beforehand, since running out of input is a foreseeable rather than an exceptional situation. However, the alternative ask-for-forgiveness style could also be acceptable.
The for-loop header does not form a coherent story — it initializes s and tests s, but updates i.
In my opinion, System.out.format() would be slightly more preferable to System.out.println() with concatenation.
I would write it as:
Scanner in = new Scanner(System.in);
int i = 0;
String s;
while (in.hasNext() && !"end".equals(s = in.next())) {
System.out.format("The value of i is: %d and you entered %s\n", i++, s);
}
It might also be a nice user interface touch to tell the user that end is a magic word to terminate the loop (assuming it were modified to work as probably intended).
The common practice with for loops is that the counter variable is repeated in each term:
for(int i=...; i<... ; i++)
In the example above, the code mixes variables. Which is confusing to the reader and probably lead to the bug that the loop only terminates if you input end as the first value.
This loop is a bad idea, because you're taking setting s once from the user input and not in every iteration.
Thus, it will cause you to run infinite time in case s was filled with value different from "end".
You probably wanted something more like this:
for (String s; (s = in.nextLine()).equals("end"); i++)
{
System.out.println("The value of i is: " + i + " and you entered " + s);
}
This isn't a good idea because the string s may never equal "end". You'll probably want to check if the scanner has another string. Also, you only initialize the string to in.next() but you need to set s to the next string after each iteration of the loop.
while(in.hasNext()) {
String s = in.next();
if (s.equals("end")) {
break;
}
// ..
}
This approach is too bad.
The Given Code :-
Scanner in = new Scanner(System.in);
int i = 0;
for (String s = in.next(); !s.equals("end"); i++)
{
System.out.println("The value of i is: " + i + " and you entered " + s);
}
The 1st part of for loop only execute once in life.
String s = in.next() //Execute only once in life
The 2nd part of this for loop never be true , because the input console will never allow to enter the 2nd input.
!s.equals("end")//2nd part
This program will never allow to enter 2nd input from console, because the in.next() will execute only once.And the exit token for this loop is "end" which is not possible to enter after first input.
This type of loops should be implemented by while loop .
Scanner in = new Scanner(System.in);
while(in.hasNext()){
String yourdata=in.next();
if(yourdata.equals("end")){
//Stop the loop
}
//Do you code here
}
It bad practice because it's terminated only if next obtained token is "end". It does'n not consider situation like. e.g. end of input stream.
So when then stream ends and nowhere along "end" appeared you'l get s=null and NullPointerException at s.equals("end").
You can correct it e.g. by changing condition to in.hasNext() && !"end".equals(s).
Also s is never changing after it was initialized.
If the question is "why rewrite it" the answer is basically as others have pointed out, that it's currently an infinite loop, and also that it's not very readable as it stands. Personally I'd rewrite it as a while loop, which several others have already pointed out how to do, as it makes your intentions a little more clear than a for loop with a counter that's counting up to infinity. Someone unfamiliar with how the code is supposed to work could easily confuse an infinite increment to be an oversight by the programmer who wrote it.
The string s is never modified. The loop never ends. What about this :
Scanner in = new Scanner(System.in);
String s = "";
for (int i = 0 ; !s.equals("end"); i++) {
s = in.next();
System.out.println("The value of i is: " + i + " and you entered "
+ s);
}
Others have mentioned that the loop does not end because you are not changing the value of s, so the loop never ends. This may be what your professor intended, and it may not be. Bad code is bad practice, as a rule, but there are other reasons why this is bad practice.
What jumped out to me as being bad practice here, and what the professor could have intended, is the use of a for loop here. As my professor told me, "For loops are for when you know when you want the code to end, while loops are for when you don't know when you want the code to end." So if you have an iterable i such as this code:
for(i = 0; i<100; i++)
{
...
}
In this code, you know that you want to iterate i from 0 to 100. A while loop is what you would want to use in the situation your professor is discussing.
int counter;
while(*(str+counter))
counter++;
You have no idea when the loop is going to end, because you don't know how long the str is, but you know that sometime it will get to the null pointer, and the loop will terminate. This generally what is best practice.
So for the code your professor posted, you may want it to look like this:
Scanner in = new Scanner(System.in);
int i = 0;
while(!s.equals("end"))
{
i++;
String s = in.next();
System.out.println("The value of i is: " + i + " and you entered " + s);
}
It is not in good practice because of two things:
for loops are meant to iterate over a collection of data
a for loop consists of iterator initial state, loop condition and an iterating function that are related
The for statement just intermixes two different information (the stream and the counter). Even if it does work, it isn't good practice to do it.
I think this is bad practice, because there isn't any need for a for loop. In this case, I believe it's useless. It could be just this:
Scanner in = new Scanner(System.in);
String s = in.next();
if (!s.equals("end"))
{
System.out.println("You have enetered" + s);
}
See, there isn't any need for a loop. The loop you had was making things more complicated than they had to be. I was always think that things should be kept as simple as they can be unless they require complexity. For loops are only to be used when you have more than one action that you want the code to do. In the case above, only one thing is happening: the println statement, so there's no need for a loop. It's unnecesary...
Also, the loop never ends. So there's that too, but that's just faulty code. That's not why it's bad practice. It's bad practice because of the unnecesary use of a for loop. It's also faulty, because the code is wrong. So there are two different things going on with this code.
I would have just left a comment, but I don't have the rep yet.
What I haven't seen explained is WHY your s value is not changing.
In a typical for loop:
for(a=1; a<=10; a+=1) {body}
the initial phrase, 'a=1', is ONLY performed once as an initialization.
the third phrase, 'a+=1', is performed once at the end of every cycle, until…
the second phrase, 'a>=10', evaluates false.
so a for loop would be represented in 'psuedo-code' something like this:
a=1 // first phrase
:LoopLabel
{body}
a+=1 // third phrase
if (a<=10) // second phrase (boolean evaluation)
then goto LoopLabel
Likewise, your example, in similar pseudo-code might look like this:
Scanner in = new Scanner(System.in);
int i = 0;
String s = in.next()
:LoopLabel
{
System.out.println("The value of i is: " + i + " and you entered " + s);
}
++i
if (!s.equals("end"))
goto LoopLabel
So the reason your program was an infinite loop was the value of 's' was only set on entry to your loop and never changed during each loop execution, as most likely desired.
for (int i = 0; in.hasNext(); i++) {
String s = in.next();
if (s.equals("end")) {
break;
}
...
Endless loop, or no loop (when s is initially "end").
A number of responses above are correct to say that what you've written is an infinite loop. But I wanted to clarify why this is an infinite loop. The for loop you're using differs from the other form you may be thinking of:
String[] stringArray = { "1", "2", "3" };
for (String s : stringArray) {
System.out.println(s);
}
In that case, the variable s is initialized with the next value from your collection or array on each iteration. But that form of for loop works with collections and arrays and can't be used with iterators like the Scanner class.
The form of for loop you're using differs in that the initialization clause (where you have String s = in.next()) is called ONLY the first time through the loop. s is set that first time, then never changed.
You could re-write like this:
int i = 0;
for (String s = in.next(); !s.equals("end"); s = in.next()) {
System.out.println("The value of i is: " + i++ + " and you entered " + s);
}
But another bad thing in here is that there's no null or end check. It's conceivable if not likely that you would run out of strings before you found one that equaled "end". If that happened, then the for test clause (the middle one) would give you a NullPointerException when it tried to the call to the equals() method. THAT is definitely bad practice. I would probably re-write this like this:
int i = 0;
while (in.hasNext()) {
String s = in.next();
if (s.equals("end")) {
break;
}
System.out.println("The value of i is: " + i++ + " and you entered " + s);
}
If you really want a for loop instead of a while, it would be better to do this:
int i = 0;
for (Scanner in = new Scanner(System.in); in.hasNext();) {
String s = in.next();
if (s.equals("end")) {
break;
}
System.out.println("The value of i is: " + i++ + " and you entered " + s);
}
One last variation that preserves the test against the string in the test clause would look like this:
int i = 0;
String s = "";
for (Scanner in = new Scanner(System.in);
in.hasNext() && !s.equals("end");
s = in.next()) {
System.out.println("The value of i is: " + i++ + " and you entered " + s);
}
You could also add a null check in there before the s.equals("end") for total safety.
It is not a good practice maybe because you are comparing the String s with a String but you are not comparing the value, you are comparing the memory position of the s value.

Categories