Java Is okay to put input/output only in main method? - java

I'm new to Java Programing.
Lately I am doing the Java assignment.
I sew this method in user-defined class
public void intputRank( Scanner s) {
salary = s.nextInt();
}
I was confused because I always want put I/O in main method (like in C++ I only write cin cout in main function). I have 2 reasons for doing this:
It's easy for me to see where my program accept input. When there is something wrong about I/O, I just need to debug the main method.
Scanner is a more complicated Class, use it as parameter would make unknown wrong.
So, kind Stack Overflowers, is it just a bad example or I understand something wrongly?
If it is the latter? Why not
public void inputRank( int asalary) {
salary = asalary;
}
//in main method
Scanner reader = new Scanner(System.in);
int asalary = reader.nextInt();
//then pass the asalary as parameter

If your program needs to be robust, e.g. when prompting for an integer it'll validate the input and re-prompt if bad, then having reusable helper methods is a good thing.
This means that you'll need multiple methods that use Scanner. Now, you can pass the Scanner object in as a parameter, or you can put it in a field, that's entirely up to you.
But the main point is that having code in a method that uses a Scanner is perfectly fine, and it really is a must for robust code, otherwise you'll ruin the DRY (Don't Repeat Yourself) principle.
Example:
public static int promptNonNegativeInt(Scanner sc, String prompt) {
for (;;) {
System.out.print(prompt + ": ");
if (! sc.hasNextInt()) {
System.out.println("** Not a valid number, please try again");
sc.nextLine(); // discard bad input
continue;
}
int value = sc.nextInt();
sc.nextLine(); // discard any extra text on the line
if (value < 0) {
System.out.println("** Number cannot be negative, please try again");
continue;
}
return value;
}
}
Example use
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int value = promptNonNegativeInt(sc, "Enter number");
System.out.println("You entered: " + value);
}
Even more complex is if you need to prompt for an object with multiple fields. Isolating the code that does this is good programming (separation of concern), so writing a promptMyObject(Scanner sc) method is a good thing.
Especially if you need to prompt for various objects. If you leave all prompting code in the main() method, it'll be huge and unreadable. It would be a God method, a variation of the God object:
A God object is an object that knows too much or does too much. The God object is an example of an anti-pattern.

In general, I prefer to write methods that take simpler types over more complicated types. This makes them easier to compose and reuse later on.
In your example, the method that takes an int could be considered better than taking a Scanner, because int is simpler and more common than a Scanner. That being said, the name inputRank kind of implies it's doing to read / receive input, so I would be tempted to rename it to something like applyRank in this case.

Related

Why do I get 'Bash (input): command not found' error when using a string for the input, but when I change that part of the code to integers, it works?

I have this program that I'm writing that mainly runs similar to a simple choose your own adventure game. It's a trouble shooting guide for rocketry, that mainly for personal use. It has simple value inputs, y/n, a,b,c,d, and so on. After a few different segments I decided to ask the user (incase I give it to friends or something) if they would like to hear a tip, if they said yes, the tip would be printed out, if not, the program would continue running. When I tested it, i got the error message: 'bash y: command not found'.
All of the syntax is correct (that was the best answer I could find to try to correct the problem, didn't apply), and I don't know what bash is, and I'm using replit, incase that matters.
I get this error in two different areas, but here is an example of one:
//problem code
class A{
public static void tip(){
Scanner scan = new Scanner(System.in);
System.out.println("Would you like to hear a tip? (y/n)");
String tipA = scan.nextLine();
if (tipA.equals("y")){
System.out.println("blahblahblah");
}
}
}
//there was a typo in this post but not in the actual code, wish it was the actual problem, thanks for pointing it out
Then I changed it to this:
//the 'fixed' code
class A{
public static void tip(){
Scanner scan = new Scanner(System.in);
System.out.println("Would you like to hear a tip? (y(1)/n(2))");
int tipA = scan.nextInt();
if (tipA == 1){
System.out.println("blahblahblah");
}
}
}
It works, but as you can see in the 'fixed' code, the y/n doesn't look as nice, and I am also curious as to why, because I could not find any answers pertaining to this scenario.
The other area is similar, but instead of "y/n", it is 'A, B, C, D' choices.
I have my current workaround, but it would be nice to have a solution to polish the program a bit.
Any help is much appreciated.
It sounds like your problem is confusion about what nextLine does. It doesn't do what 99% of java programmers (and most tutorials) think it does. It's not a bug - it does exactly what the javadoc says, but, it's not what you'd expect.
See This answer that explains precisely what to do. Boils down to:
public static void tip() {
Scanner scan = new Scanner(System.in);
scan.useDelimiter("\\R");
System.out.println("Would you like to hear a tip? (y/n)");
String tipA = scan.next();
if (tipA.equals("y")) {
System.out.println("blahblahblah");
}
Generally you'd want to make a scanner exactly once (in your main method perhaps), create a new instance of your Main class, set up the Scanner as a field of it, and then reuse it in all your methods. This saves typing, is easier to test, more flexible, etc:
public class ExampleMain {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
s.useDelimiter("\\R");
ExampleMain app = new ExampleMain();
app.scanner = s;
app.go();
}
private Scanner scanner;
private boolean running;
void go() {
running = true;
while (running) {
tip();
// whatever other commands and such you'd like go here
}
}
void tip() {
System.out.println("Would you like to....");
}
}
This also lets you do things like write a method that repeatedly asks for a specific kind of input (say, an integer between 1 and 9, as you're showing a menu with 9 options), and, using a while loop, keep asking if the user fails to enter appropriate responses. Otherwise you have to copy/paste a ton of code which is naturally not how you should be programming.

What's a better or more standard way to perform this function?

I am a java beginner, and in this particular problem I practiced making a program that converts any given string to lowercase string. Is there a a better way to achieve this goal in java (in terms of design)?
Also, how does the "else" (after "else if") catches or waits for me to make an input. Somehow that part does not make sense to me, even though I achieved what I wanted. How is the value of "ans" from input transferred to the entire loop and used until the loop is closed?
After many attempts and failures, I used a separate method for the conversion part. My second question is a bit too complicated to be researched.
import static java.lang.System.out;
import java.util.Scanner;
public class MyClass {
public static Scanner s = new Scanner(System.in);
public static String ans;
public static void main(String args[]) {
Conversion();
do {
ans = new String(s.nextLine());
if (ans.equalsIgnoreCase("Y")) {
Conversion();
} else if (ans.equalsIgnoreCase("N")) {
out.println("Thank you for using this program!");
break;
} else {
out.println("Invalid entry!");
out.println("Would you like to convert another string?\n(Please type 'Y' for yes, or 'N' for no.)");
}
} while (ans != "N");
}//END MAIN
public static void Conversion() {
out.println("Please enter string to be converted to lowercase: ");
String str = new String(s.nextLine());
out.println("Your new string is: " + str.toLowerCase());
out.println("Would you like to convert another string? (Y/N)");
}
}
I notice a few issues; Conversion looks like a class-name (Java naming convention would be conversion) and ans != "N" is using == instead of .equals - and wouldn't ignore case (!ans.equalsIgnoreCase("N")). Globals (e.g. static) are bad (pass the Scanner to the methods that need it), and the static import just makes the code more difficult to reason about (in my opinion). Your current loop doesn't really follow a conventional form, I would extract the prompt and loop for "another" conversion to a new method and if you must print a thank you I'd do so after the "main loop". Something like,
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
do {
conversion(sc);
} while (another(sc));
System.out.println("Thank you for using this program!");
}
public static void conversion(Scanner s) {
System.out.println("Please enter string to be converted to lowercase: ");
System.out.printf("Your new string is: %s%n", s.nextLine().toLowerCase());
}
public static boolean another(Scanner s) {
while (true) {
System.out.println("Would you like to convert another string? (Y/N)");
String ans = s.nextLine();
if (ans.equalsIgnoreCase("Y")) {
return true;
} else if (ans.equalsIgnoreCase("N")) {
return false;
}
System.out.println("Invalid entry!");
System.out.println("(Please type 'Y' for yes, or 'N' for no.)");
}
}
Answering your first question:
There are many design patterns and practices so many people can argue what I would recommend you to do. It's basically the same for all programming languages. Let's take your function "Conversion". The name itself says that you use it to convert stuff. Not to display, not to prompt - to convert. In this case, the only actual thing it should do is to convert upperCase to lowercase. In fact, you might want to specify what type of conversion it has in the name of the function (convertToLowerCase?). In fact, in Java, we use lowerCamelCase for all function names and UpperCamelCase for classes.
If you accept my previous suggestion, you could break the Conversion function into multiple ones like promptUserForInput, WrongInputHandler and so forth.
If I understood your second question correctly, you wonder about the way the code executed and how the variable ans is transferred further into the loop. Let's take a look at your code and what variables do:
You initialize your variable in the class MyClass by making it accessible to all methods in the class;
You prompt the user for the input to assign to this variable inside the do..while loop with this line ans = new String(s.nextLine()); which saves the value of the variable and, again, which can be accessed inside the whole class so its value is changed.
It goes into the if..else if...else statement. The way it works, it goes line by line - if the first if-statement fails, it goes on until it finds a truthy statement and it doesn't go any further. In your case, if the ans is not equal to either y/Y/ it will go to else if statement and if it's not n/N, it will go to else (so basically whatever except y/Y/n/N) and will be executed. After that, it jumps into the while (ans!= "N"); line where it compares your class-member variable ans and if it's not equal to "N" it starts over the loop right after the do{ part until you type in the "N".
I hope that makes sense. Whenever the program is asking you for input, it does not execute code further but is stuck until you provide any input. The value from input itself isn't passed throughout the loop and the program. The reason why you can use it because you created a higher-scope variable ans where you saved the result of your input.
IMPORTANT: if you've declared the ans inside the do..while loop, you would've not been able to have accessed it in the while (ans...) because it will 'die' right before the curly brace between do { ...here} while(). If you want to learn more about the scope and variables in general, you can read this article.
Here is my code example:
public static void main(String args[]) {
//declare before entering the loop to have higher scope
String ans = "y";
do {
//we get the given string to convert from the user
String str = promptForString();
//we convert the string
str = converseStringToLowerCase(str);
//display the string (could use another function for that: easier to debug and locate problems and in bigger projects)
out.println("Your new string is: " + str);
//prompt user for respond to continue or not
ans = promptForContinue();
handleResponse(ans);
} while (!ans.equals("n"));
}//END MAIN
//prompts user for an input string
public static String promptForString() {
out.println("Please enter string to be converted to lowercase: ");
String str = new String(s.nextLine());
return str;
}
//converts any given string to lower case
public static String converseStringToLowerCase(String str) {
return str.toLowerCase();
}
//is used to prompt user for reply
public static String promptForContinue() {
out.println("Would you like to convert another string? (Y/N)");
String str = new String(s.nextLine());
//is good to make if...else statements easier - it will always be lower case (or upper if you prefer)
return str.toLowerCase();
}
//easier to locate other response scenarios
public static void handleResponse(String response) {
if (response.equals("n")) {
out.println("Thank you for using this program!");
//it's not a very good practice to innaturally break loops. Use input for that in while(..) statement
// break;
} else if (!response.equals("y")) {
out.println("Invalid entry!");
out.println("Would you like to convert another string?\n(Please type 'Y' for yes, or 'N' for no.)");
}
}

Want to programm calculator, want to change String into real operator

I want to code a simple calculator and already got some code. But now I want to change the String I got there into an Operator. For example:
My input is: "1,5 - 1,1 + 3,2 ="
Now I have a double array and a String array.
So after that I want to put it together, so it calculates this complete task.
double result = double[0] String[0] double[1] ....
I hope you can help there, and I apologize for my grammar etc., english is not my main language.
import java.util.*;
public class calculator
{
public static void main(String[] args)
{
int a = 0;
int b = 0;
double[] zahl;
zahl = new double[10];
double ergebnis;
String[] zeichen;
zeichen = new String[10];
Scanner input = new Scanner (System.in);
while (input.hasNext())
{
if (input.hasNextDouble())
{
zahl[a] = input.nextDouble();
a++;
}
else if (input.hasNext())
{
zeichen[b] = input.next();
if (zeichen.equals ("=")) break;
b++;
}
}
input.close();
}
}
If I type in: "1,5 + 2,3 * 4,2 =" I want to get the result with point before line and without .math
What you want to do is parse a single String and convert it into a mathematical expression, which you then want to resolve and output the result. For that, you need to define a "language" and effectively write an interpreter. This is not trivial, specifically if you want to expand your syntax with bracketing and thelike.
The primary question you have to answer is, whether you want to use a solution (because you are not the first person to attempt this) or if you want to actually write this yourself.
There are "simple" solutions, for example, you could instantiate a javascript engine in Java and input your string, but that would allow much more, and maybe even things you don't want. Or you could use a library which already does this. This Thread already answered a similar question with multiple interesting answers:
How to evaluate a math expression given in string form?
Otherwise, you might be in for a surprise, concerning the amount of work, you are getting yourself into. :)

Why is this code keep being "terminated"?

I have this code in Eclipse:
package test;
import java.util.Scanner;
class test{
public static void main(String args[]){
Scanner Input = new Scanner(System.in);
if (Input.equals("payday2")){
System.out.println(Input);
}
}
}
Now when I try to start the code/aplication, it terminates itself.
Any ideas why that happens?
You instantiate the Scanner as a variable named Input but never try to read.
Your condition
if (Input.equals("payday2")){
will only check if the Scanner object is equals to the string "payday2" which will always be false, hence the program terminate.
If you want to read, you need to do Input.nextLine().
I dont know about eclipse, but Netbeans would give a warning "equals on incompatible type" with this line.
Also, you should not name your variable with a capital letter as by convention, only class name should start with a capital.
So your fixed program would be
Scanner input = new Scanner(System.in);
String value = input.nextLine();
if ("payday2".equals(value)) {
System.out.println(value);
}
Notice that I kept the string in a variable to display it as displaying input would call toString of the Scanner object which is probably not what you expected.
Notice that I also compared the string in reverse order which is a good practice to avoid NPE even if not really needed here.
You never read input from the Scanner instance so the application doesnt block
String text = input.nextLine();
if ("payday2".equals(text)) {
...
I think you mean to do:
String in = Input.nextLine();
if(in.equals("payday2"))
{
System.out.println(in);
}
Note: in Java 7 you can do the following:
String in = Input.nextLine();
switch(in)
{
case "payday2":
System.out.println(in)
break;
case "payday the heist":
//...
break;
}
Which makes it much easier to manage different input cases.

Multiple Methods

I'm trying to create my own methods to use in my main method. I have asked the user for input in my main method and have captured it using next line. However, I am unable to use it in my other methods.
static Scanner keyboard = new Scanner(System.in);
public static void main (String[] args) {
System.out.println("Input string of any length");
String s = keyboard.nextLine();
System.out.println("If you want to the program to check if palindrome, type 1."+
" If you want the program to compute rounded sum, type 2. If you want " +
"the program to count unique characters, type 3");
String o = keyboard.nextLine();
if (o.equals("1"))
System.out.println(isPalindrome());
}
public static boolean isPalindrome () {
boolean palindrome = true;
String s = keyboard.nextLine();
It is asking me to redefine string s, in my other method, even though it has already been defined in the main.
This is because of variable scope. Each variable only exists in a certain part of the program and other parts can have different variables with the same name that only exist in that part.
There are plenty of tutorials around on the subject. For example:
http://docs.oracle.com/javase/tutorial/java/javaOO/variables.html
http://www.java-made-easy.com/variable-scope.html
http://www.cs.berkeley.edu/~jrs/4/lec/08
Adding on to Tim B's answer, it is always good to make a function full and sound.
i.e. instead of
public static boolean isPalindrome ()
Use
public static boolean isPalindrome (String text)
and pass in the text you want to check for palindrome. This makes the function more complete. Treat a function like asking someone a question. "Is this text a Palindrome?" instead of "Is Palindrome?".

Categories

Resources