I'm getting the error
the local variables name and password may not have been initialized,
for the if-statement. These errors go away if I change the second string in parentheses to something in quotes, or if I set the variables to 0, but then I would also need to change them to int and I need them to be String.
I'm trying to compare the username and password from a text file to a newly input username and password. The program should also quit after 3 bad attempts so I probably put the System.out.println("Goodbye!"); in the wrong place too.
public static void main(String[] args) {
int numberOfAttempts = 1;
String fileName = "logins.txt";
Scanner inputStream = null;
String name, password, line, secondname;
String secondpassword;
do
{
System.out.println("Please enter your username: ");
Scanner keyboard = new Scanner(System.in);
secondname = keyboard.nextLine();
System.out.println("Please enter your password: ");
secondpassword = keyboard.nextLine();
try
{
inputStream = new Scanner(new File(fileName));
}
catch(FileNotFoundException e)
{
System.out.println("Error opening the file " +
fileName);
System.exit(0);
}
while (inputStream.hasNextLine())
{
line = inputStream.nextLine();
}
if ((name.equalsIgnoreCase(secondname))&&
(password.equalsIgnoreCase(secondpassword)))
{System.out.println("Welcome!");
numberOfAttempts = 4;
}
else
System.out.println("Invalid. Please try again.");
numberOfAttempts++;
}
while ( numberOfAttempts <4);
System.out.println("Goodbye!");
inputStream.close();
}
}
You never initialize name and password, so of course you'll get this error.
You initialize secondname and secondpassword, but your condition checks name and password which are not initialized.
In JAVA methods, any local variable must be initialized first it can be used. In your case you are trying to compare the name & password in your code are never initialized or assigned a value.. It will be a good idea to initialize your strings either as NULL or empty string such as "" or any desired value.
You have a bunch of problems.
The errors are caused by the fact that you never assign any values to the variables "name" and "password", but you then check to see if those variables match the secondname and secondpassword variables you do read. Because name and password never get any values at all, the comparison can't possibly be what you intend, so the compiler flags it as an error.
You can make the error go away by assigning name and password to some values when you declare them, but your program still isn't going to work correctly, because no matter what value you assign, it probably won't be the thing that the user of your program would want to be comparing against.
Presumably your intent is to read the value of name and password from the input file you've opened and read in, but in fact you aren't doing anything with the values in that file except immediately throwing them away. Look at the loop
while(inputStream.hasNextLine()) {
line = inputStream.nextLine();
}
This loop will read in every line from the file, but as soon as you read one line, you throw away whatever you read into the line variable because you have to reuse that variable to read the next line, which you'll also throw away immediately. At the end of the loop, you'll have saved the last line from the file into line, but the rest of the program doesn't use the line variable either.
You need to put some logic inside that loop to read whatever you wanted to read from the file, store it in the name and password variables, and then you'll have some hope that when you do the equalsIgnoreCase stuff that you'll actually be comparing variables that have some meaning to your program.
Related
So i have a program that creates a new file but need it to have a default file name if the user was to not enter anything, and was wondering if anyone could help with it.
So far i have the program asking the user for the file name but not sure what to do to set the default to for say "output.txt".
Here is a snip-it of my code:
//Creates a Scanner Object for keyboard input.
Scanner keyboard = new Scanner(System.in);
//Get the filename.
System.out.print("Enter a filename: ");
filename = keyboard.nextLine();
Test what the user has entered as a filename. If it is an empty string, use the default filename.
You may want to "trim" the string too. A filename with leading or trailing whitespace characters would be a bad idea.
You have to test if the string is empty, which can be done with String#isEmpty in conjuction with String#trim, from the documentation:
isEmpty
public boolean isEmpty()
Returns true if, and only if, length() is 0.
That means, once we trim to remove whitespace, we can test if length is 0. Thus, any inputs that consist of just spaces will not be used as filenames, and will default, else it will used the given. You can apply this like so:
File file = new File(filename.trim().isEmpty() ? "output.txt" : filename);
try {
file.createNewFile();
} catch(IOException ex) {
//file was not created successfully
}
This will create a new File object, which will have a filename based on if the user inputted anything (whitespace excluded). file.createNewFile() will just create the file if it does not exist.
It's sure you need some condition for achieve this.
Perhaps, you probably need simple method like this:
isNotNullOrEmpty(filename) ? filename : defaultFileName;
private static boolean isNotNullOrEmpty(String str) {
return str != null && !str.isEmpty();
}
This question serves as a follow-up to a previous question.
I am trying to create a program that converts from one currency to another.
First, I'll post and explain the relevant code, then describe the desired outcome and some problems I came across.
do {
try {
invalidInput = false;
String line = input.nextLine();
Scanner lineScan = new Scanner(line);
BigDecimal moneyInput = lineScan.nextBigDecimal();
// second do-while loop that tries to emulate the outermost do-while loop
// introduces a second set of nested scanners
// re-prompts user for valid currency if they try a blank input
do {
try {
String line2 = input.nextLine();
Scanner lineScan2 = new Scanner(line2);
String currency = lineScan2.next();
if (currency.equals("USD")) {
// convert USD to CNY
} else if (currency.equals("CNY")) {
// convert CNY to USD
}
} catch (NoSuchElementException e) {
invalidInput = true;
System.err.print("Please enter a valid CURRENCY: "); // prompts user for currency ONLY
}
} while (invalidInput);
} catch (NoSuchElementException e) {
invalidInput = true;
System.err.print("Please enter the VALUE followed by the CURRENCY: ");
}
} while (invalidInput);
The outer do-while loop runs as long as invalidInput is true. At the beginning of the first try block, invalidInput is false, and it remains false unless the user enters an invalid input (e.g. blank input or non-numeric). Here, invalidInput becomes true, and the program loops back to the top of the try block after re-prompting the user for both moneyInput and currency.
Next, I wanted to find someway to check the validity of moneyInput and currency separately. The first set of nested Scanners is meant to process moneyInput. If the user inputs something invalid, it will re-prompt the user Please enter the VALUE followed by the CURRENCY:, and it will continue to do so until something valid is entered.
I then wanted to add the exact same functionality to check currency exclusively. This is the intended purpose of the second set of nested scanners (lineScan2). If a valid input is entered for moneyInput but not for currency, e.g. 100.00 abc, I'd like the program to retain the value of moneyInput, re-prompt the user for only currency, and continue to do so until a valid currency is entered (including if the user enters a blank input).
Here are some problems I'm running into:
The program is only reading moneyInput in the first line, instead of reading both moneyInput and currency. Secondly, for each input, the user must press [return] twice (note each of the empty lines in between each input).
The program also terminates inconsistently. In the image example above, after it finally accepts a valid moneyInput and currency and converts the value, the program does not terminate. It terminates prematurely if the moneyInput is entered first, followed by an invalid currency on a second line, like so:
But here, it terminates properly after a successful run (although this still isn't exactly right because it only is "successful" if moneyInput and currency are input on separate lines; ideally, the user should be able to enter both on the same line and the program prints the appropriate conversion):
However, one thing the program does do well is responding repeatedly to invalid (specifically, blank inputs):
And actually, in the case above, aside from the fact that [return] had to be entered twice when prompting for moneyInput and that it didn't terminate after a successful run, everything is working exactly as desired:
the user gets to try repeatedly until a valid input, and in the case
where moneyInput is valid but currency is not, the user only has
to enter a valid input for currency (i.e. they don't have to
re-enter moneyInput when only the currency was invalid).
So overall I am looking for ways to modify the code above to achieve the desired results. As mentioned in the comment section of the linked question at the very top of this post, another method I tried was another do-while loop inside (in place of the inner do-while loop) to check currency, and this worked except for when a blank input was entered, which is basically problem I had at the beginning of that post (here is my code: pastebin.com/raw/CT0qjBPk and example screenshots: imgur.com/a/mjfaL).
Sorry if this post is excessively specific and lengthy. I am a beginner programmer and trying to study Java as thoroughly as possible, and this process of improving code has been of great educational value. Thanks so much for reading and providing feedback.
Your implementation is overly-complex because you're using input in several different places. Here's essentially the pattern I suggested in my answer to your previous question:
try (Scanner in = new Scanner(System.in)) {
while (in.hasNextLine()) {
String line = in.nextLine();
doSomethingWithALineOfInput(line);
}
}
Here's roughly what your code is doing:
boolean invalidInput = false;
try (Scanner in = new Scanner(System.in)) {
while (in.hasNextLine()) {
do {
String line = input.nextLine();
invalidInput |= doSomethingWithALineOfInput(line);
do {
String line2 = input.nextLine();
invalidInput |= doSomethingWithASecondLineOfInput(line2);
} while (invalidInput);
} while (invalidInput);
}
}
Notice in particular that you're calling input.nextLine() in two separate places, which makes your code hard to reason about. One of the primary goals when programming is to reduce your problem into smaller subproblems - interleaving input.nextLine() calls everywhere (let alone inside nested do-while loops) forces you to continue dealing with one big problem.
So instead of mixing your line-processing and your token-processing code together, isolate them from each other. The only thing that should interact with input is the very outer while loop. Once you've read a line you're done with input for the remainder of that iteration.
Consider something like this (notice the use of a class to contain the values as we read them in):
class PromptForMoney {
private BigDecimal amount;
private String currency;
public void prompt(Scanner in) {
System.out.print("Enter an amount of money and currency to convert: ");
while (in.hasNextLine()) {
try {
processLine(in.nextLine());
return;
} catch (InputMismatchException | NoSuchElementException e) {
// we use the exception message to describe the problem to the user
// if Scanner generates exceptions with unclear messages you can
// catch them in processLine() and throw your own with a better message.
System.out.print("Invalid input - " + e.getMessage() + ": ");
}
}
throw new NoSuchElementException(
"No more input to read, but a valid amount or currency was not entered.");
}
private void processLine(String line) {
Scanner lineScanner = new Scanner(line);
if (amount == null) {
// this line will raise an exception if the line is empty
// or if it doesn't start with numerical token
amount = lineScanner.nextBigDecimal();
}
if (currency == null) {
// this line will raise an exception if the user didn't specify a currency
String c = lineScanner.next();
if (isValidCurrency(c)) {
currency = c;
} else {
throw new InputMismatchException(c + " is not a valid currency");
}
}
// if we get this far without raising an exception we've read a valid
// amount and currency from the user.
}
}
Notice how prompt() deals solely with lines, and processLine() deals solely with the contents of a single line. This cleanly separates the problem into smaller, easier-to-reason-about parts.
You'd use PromptForMoney like so:
public static void main(String[] args) throws IOException {
PromptForMoney prompt = new PromptForMoney();
try (Scanner in = new Scanner(System.in)) {
prompt.prompt(in);
}
System.out.println(convert(prompt.getAmount(), prompt.getCurrency());
}
There's another separation of concerns - only main() is responsible for directly interacting with System.in. As far as PromptForMoney is concerned its Scanner could be backed by a string or a file and it would work exactly the same.
Caveat: there are some best practices I'm not emphasizing for the sake of space and simplicity (e.g. preferring final instance variables). If you're interested in improving your code quality even further I strongly suggest reading Effective Java which goes into great detail about Java design patterns.
This method is supposed to return the integer that the user enters as long as it is only an integer (not a String, float, etc.) and as long as that integer is one of the options in the given list of options. I want to use this method throughout my program whenever I give the user a list of options they need to choose from. These lists will have varying sizes thus I pass as an argument the maximum value (maxValue) that the user could possibly choose thus giving the method the size of the list.
//This method handles the players input and checks if the number entered is one of the options listed or not
public static int response(int maxValue){ //the parameter is the number of options in the particular list
response = new Scanner(System.in);
Boolean check = true;
while(check){
try{
int yesOrNo = response.nextInt();
if(yesOrNo > maxValue || yesOrNo <= 0){ //checks if the int entered does not exceed the list size or go below zero
System.out.println("I'm sorry, that number was not one of the options. Please reselect your choice.");
}else{
check = false;
}
}catch(Exception e){ //catches an exception when the user enters a string or anything but an int
System.out.println("Please only use digits to make a selection.");
response(maxValue);
}
}
return yesOrNo; //returns the user's response. Well, it is supposed to.
}
I am a beginner with regards to programming. I am learning Java through online tutorials and trial and error on dumb, little programs I make. I am working on a fun little text-adventure and am still in the beginning stages.
The trouble I'm having is because this method will only return 0. Isn't yesOrNo being assigned the integer that the user inputs through the scanner response? Why is it only returning 0?
Thank you for your responses. I understand now that I needed to declare my int yesOrNo outside of the try because it was out of scope, as you all put it, being declared within.
BUT a few mentioned 'there is a completely unnecessary function call in the catch block'. The only problem is if I remove it there is an infinite loop created with the System.out.println("Please only use digits to make your selection.") when the user inputs Strings or other non-int values.
Here is my updated code:
//This method handles the players input and checks if the number entered is one of the options listed or not
public static int response(int maxValue){ //the parameter is the number of options in the particular list
response = new Scanner(System.in);
Boolean check = true;
int yesOrNo = 0;
while(check){
try{
yesOrNo = response.nextInt();
if(yesOrNo > maxValue || yesOrNo <= 0){ //checks if the int entered does not exceed the list size or go below zero
System.out.println("I'm sorry, that number was not one of the options. Please reselect your choice.");
}else{
check = false;
}
}catch(Exception e){ //catches an exception when the user enters a string or anything but an int
System.out.println("Please only use digits to make a selection.");
response(maxValue);
}
}
return yesOrNo; //returns the user's response. Well, it is supposed to.
}
After reading other post before just asking another question I found many others facing the same issue. It was correct what some were saying that the infinite loop was created because when the Scanner encounters an error it doesn't remove the token of that error thus causing the while loop to read the same error over again infinitely. Here is what i read exactly:
"As per the javadoc for Scanner:
'When a scanner throws an InputMismatchException, the scanner will not pass the token that caused the exception, so that it may be retrieved or skipped via some other method.'
That means that if the next token is not an int, it throws the InputMismatchException, but the token stays there. So on the next iteration of the loop, getAnswer.nextInt() reads the same token again and throws the exception again. What you need is to use it up. Add a getAnswer.next() inside your catch to consume the token, which is invalid and needs to be discarded."
So now that infinite loop problem is fixed :) Onto finding what else I need to learn. Thank you.
yesOrNo goes out of scope because you declared it within the try block. Move the declaration outside to where it is in scope when you return it.
Boolean check = true;
int yesOrNo;
yesOrNo you're returning is not same as
int yesOrNo = response.nextInt();
in your loop. The yesOrNo from the loop disappears (goes out of scope) at the closing } of try.
There has to be another int yesOrNo somewhere. Look for it.
The only this can compile is if yesOrNo is declared as a class or instance variable, unseen in this code snippet.
The declaration of yesOrNo that we do see is declared inside a try block, shadowing the yesOrNo being returned. But there's no reason for it to be a class or instance variable.
Remove it from the class declaration, and declare it locally, before the try block, so it's in scope when it's returned.
int yesOrNo = 0;
try{
yesOrNo = response.nextInt();
I see "int yesOrNo" inside while loop. The value read inside while loop scope is limited to that. Declare that variable outside and try.
I will admit, this is a school assignment... But I simply cannot figure out what I am doing wrong.
I have a hash table with an insert function. The following code is supposed to take a line of data from System.in in the format "Long String" (i.e. "32452 John"). The first token must be a Long for the ID number, and it must be followed by a String token for the name. When I run the program and I get to the portion where this must be executed (It is in a switch statement), I entered 'a' and hit enter. The command line immediately reads "Invalid value." (note: not VALUES, as that would mean it hit the nested if statement. It won't let me type in any data. Thank you in advance!
System.out.println("Enter ID and Name.");
//temp to take in the next line entered by the user
//inScan is the Scanner for System.in
temp = inScan.nextLine();
//Create Scanner for the line
Scanner tempScan = new Scanner(temp);
if(tempScan.hasNextLong()){
thisID = tempScan.nextLong();
if((tempScan.hasNext()) && (thisID>0)){
thisName = tempScan.next();
//The data will only be inserted if both segments of data are entered
myTable.insert(new Student(thisID, thisName));
}else{
System.out.println("Invalid values.");
}
}else{
System.out.println("Invalid value.");
}
Why do you need the second Scanner?
Example
String input = scanner.nextLine();
String[] tokens = input.split(" ");
Long id = Long.parseLong(tokens[0]);
String name = tokens[1];
And if you wanted to add your validation:
String input = scanner.nextLine();
if(input.contains(" ")) {
// You know there's a space in it.
String[] tokens = input.split(" ");
if(tokens.length == 2) {
// You know it's a value, followed by a space, followed by a value.
if(tokens[0].matches("[0-9]+")) {
// You know it only contains numbers.
Long id = Long.parseLong(tokens[0]);
}
}
}
I've not run it, but i guess your problem is that when you enter the text 'a' and hit enter, this line is false:
if(tempScan.hasNextLong()){
as you haven't entered a number. hence why it drops to the next block. If you enter something numerical first, i suspect your code with work. you probably need to add a 'while' loop around it, to run until it gets a number.
You already have a Scanner which reads from System.in, there's no need for another one. The second one you've made is a scanner for a String, which will never have a nextLong as it has nothing to scan after your String.
I won't write any code for you as this is homework, but stick to your original scanner when checking for user input instead.
(First of all, I apologize if this is a basic question, but I'm new to coding)
What i want to do is to verify whether a string as a certain combination of characters and then replace them using an if-else statement, like this:
String RAWUserInput = sometextfield.getText().toString();
if (RAWUserInput.contains("example") {
String UserInput = RAWUserInput.replace("example", "eg");
}else{
String UserInput = RAWUserInput;}
sometextbox.setText(UserInput);
and then access the string outside of the if-else statement. I don't know how to do the last line because java can't find the string, What should I do?
Thanks in advance :)
Declare the variable before the if statement.
String UserInput;
if (RAWUserInput.contains("example") {
UserInput = RAWUserInput.replace("example", "eg");
}else{
UserInput = RAWUserInput;
}
It will remain in scope after the if statement. If the variable is declared inside the if block or else block (in between the braces), then it goes out of scope after the end of the block.
Also, the compiler is smart enough to determine that something is always assigned to UserInput in every case, so you won't get a compiler error that the variable may not have been assigned a value.
In Java, variables are typically named starting with a lowercase letter, unlike classes. Normally, your variables would be named userInput and rawUserInput.
When you declare a variable inside a block ({ ... }), the variable only exists inside that block.
You need to declare it outside the block, then assign it inside the blocks.
String rawUserInput = sometextfield.getText().toString();
String userInput = ""; // empty
if (rawUserInput.contains("example") {
userInput = rawUserInput.replace("example", "eg");
} else{
userInput = rawUserInput;
}
sometextbox.setText(userInput);
Otherwise, save the else statement:
String rawUserInput = sometextfield.getText().toString();
String userInput = new String(rawUserInput); // copy rawUserInput, using just = would copy its reference (e.g. creating an alias rawUserInput for the same object in memory)
if (rawUserInput.contains("example") {
userInput = rawUserInput.replace("example", "eg");
}
// no else here
Also, have a look at coding guidelines: indenting your code makes it more readable, starting temporary variable names with a lowercase is preferred.
String UserInput = RAWUserInput.contains("example")? RAWUserInput.replace("example", "eg"): RAWUserInput;