Java: Looping issue within my file reading program - java

I've only been coding for a couple months so I'm still fairly new.
I'm writing a program using Java in Eclipse IDE that reads a file containing data about the changing popularity of various baby names over time and displays the data about a particular name (which is entered via keyboard by the user). Each line of the file stores a name followed by integers representing the name's popularity in each decade: 1900, 1910, 1920, and so on. My program prompts the user for a name, searchs the file for that name, and displays the data for that name from the file to the screen.
Example of data from txt file: Sam 58 69 99 131 168 236 278 380 467 408 466
Example of what should be displayed on screen:
Statistics on name "Sam"
1900: 58
1910: 69
1920: 99
1930: 131
...
This is my program:
public class fileAndExceptionHanding {
public static void main(String[] args) throws IOException {
Scanner keyboard = new Scanner(System.in);
FileInputStream fileByteStream = null;
Scanner inFS = null;
String userName = "";
String fileName = "";
File file = new File("names.txt");
List<Integer> numNamesOfYear = new ArrayList<Integer>();
boolean repeatSearch = true;
boolean repeatNameSearch = true;
int startingYear = 1900;
int yearCounter = startingYear;
char userKey;
fileByteStream = new FileInputStream("names.txt");
inFS = new Scanner(fileByteStream);
if (!file.exists()) {
file.createNewFile();
}
System.out.println("This program allows you to search through the data from the Social
Security Administration to see how popular a particular name has been since 1900.");
do {
System.out.println("Name? ");
userName = keyboard.next();
do {
while (!(fileName.equals(userName)) && inFS.hasNextLine()) {
fileName = inFS.next();
}
if (!(fileName.equals(userName))) {
System.out.println("Error! Name was not found. Please enter another name for our
system to search.");
userName = keyboard.next();
repeatNameSearch = true;
}
else {
repeatNameSearch = false;
}
} while (repeatNameSearch);
while (inFS.hasNextInt()) {
numNamesOfYear.add(inFS.nextInt());
}
System.out.println("Statistics on name " + "\"" + userName + "\"");
yearCounter = startingYear;
for (int i = 0; i < numNamesOfYear.size(); ++i) {
System.out.println(" " + yearCounter + ": " + numNamesOfYear.get(i));
yearCounter += 10;
}
numNamesOfYear.clear();
System.out.println("If you would like to search another name for popularity data,
please enter \"y\" to continue.");
System.out.println("If you wish to exit, please press any other key.");
userKey = keyboard.next().charAt(0);
if (!(userKey == 'y' || userKey == 'Y')) {
repeatSearch = false;
}
}while (repeatSearch);
fileByteStream.close(); // Closing file and input stream.
keyboard.close(); // Closing keyboard scanner.
inFS.close(); // Closing file scanner.
}
}
My program is running perfectly at first until the prompt for the user to enter "y" to continue or any other key to exit. When I enter "Y/y" and enter another name to search, my program doesn't repeat the name search and instead displays my "error invalid name, please enter a different name to search" message even though the name I entered is valid and inside the txt file.
Example of another name and data within the txt file that I tried to repeat search for:
Abbey 0 0 0 0 0 0 0 0 537 451 428
If you would like to search another name for popularity data, please enter "y"
to continue.
If you wish to exit, please press any other key.
y
Name?
Abbey
Error! Name was not found. Please enter another name for our system to search.
Entering "Sam" gives me correct data but if I press y to repeat loop and enter "Sam" again, it prints the following (Skips year data output):
This program allows you to search through the data from the Social Security Administration to see how popular a particular name has been since 1900.
Name?
Sam
Statistics on name "Sam"
1900: 58
1910: 69
1920: 99
1930: 131
1940: 168
1950: 236
1960: 278
1970: 380
1980: 467
1990: 408
2000: 466
If you would like to search another name for popularity data, please enter "y"
to continue.
If you wish to exit, please press any other key.
y
Name?
Sam
Statistics on name "Sam"
If you would like to search another name for popularity data, please enter "y"
to continue.
If you wish to exit, please press any other key.
I assume the problem lies somewhere within my loops, however it's proving difficult for me to find.
Any help or advice on where my looping problem lies would be greatly appreciated!
Thank you in advance.

Related

How do I fix a NumberFormatException (from text file input)?

I was wondering if I could have some help with this NumberFormatException with code using a text input.
The result should be it being able to run properly and be able to first put 50 strings into the hashTable and then remove 10 afterwards.
I have tried placing the removeLine.next() inside a String datatype and then placing the String back inside the Integer.parseInt which didn't work.
Here is the class:
import java.io.*;
import java.util.*;
public class hashTest {
public static void main(String args[]) throws FileNotFoundException {
HashTable hashTable = new HashTable();
Scanner insert = new Scanner(new File("data1.txt"));
while(insert.hasNext()) {
String line = insert.nextLine();
Scanner insertLine = new Scanner(line);
insertLine.next();
insertLine.next();
int index = Integer.parseInt(insertLine.next());
String data = insertLine.nextLine();
hashTable.put(index, data);
}
Scanner remove = new Scanner(new File("data2.txt"));
while(remove.hasNext()) {
String line = remove.nextLine();
Scanner removeLine = new Scanner(line);
removeLine.next();
removeLine.next();
int index = Integer.parseInt(removeLine.next());
hashTable.remove(index);
}
}
}
data1.txt :
003 : 68682774 MALIK TULLER
004 : 24248685 FRANCE COELLO
005 : 25428367 DUSTY BANNON
006 : 79430806 MELVINA CORNEJO
007 : 98698743 MALIA HOGSTRUM
008 : 20316453 TOMASA POWANDA
009 : 39977566 CHONG MCOWEN
010 : 86770985 DUSTY CONFER
011 : 92800393 LINNIE GILMAN
012 : 31850991 WANETA DEWEES
013 : 81528001 NEAL HOLSTEGE
014 : 46531276 BRADLY BOMBACI
data2.txt :
92800393 LINNIE GILMAN
86770985 DUSTY CONFER
31850991 WANETA DEWEES
46531276 BRADLY BOMBACI
25428367 DUSTY BANNON
68682774 MALIK TULLER
18088219 PENNY JOTBLAD
48235250 KENNITH GRASSMYER
20316453 TOMASA POWANDA
54920021 TYSON COLBETH
22806858 LAVERNE WOLNIK
32244214 SHEMEKA HALLOWAY
81528001 NEAL HOLSTEGE
24248685 FRANCE COELLO
23331143 JUSTIN ADKIN
79430806 MELVINA CORNEJO
59245514 LESLEE PHIFER
64357276 SCOT PARREIRA
50725704 GENARO QUIDER
52298576 AUDIE UNCAPHER
54657809 MARTY ENOCHS
54526749 TOBI HEATLEY
24903965 ALONSO GILSTAD
84936051 DEONNA STRAZZA
62522327 AHMAD THAYER
90572271 ELIJAH METEVIER
88999386 ISMAEL ELKAN
NumberFormatExceptions with Integer.parseInt() are most often caused by attempting to read something into an int that is not actually an int. Try printing each line as it is read in. If you have a line that is not purely an int (e.g., Hello123), you will get this exception with Integer.parseInt(). A cleaner debugging method (and better coding practice) would be to catch the exception and print the problematic line. You will probably see right away what's causing the issue. When reading text input from anywhere, it's never good to assume that the data is of the format you're expecting.
When your input contains data other than the int values you need, you can read each line's values into an array and extract the proper value(s). Here's an example of how you might extract the values from a single line in your second data file. Keep in mind that this still makes assumptions about the input format and therefore, is not completely fool-proof.
try {
// Split the line by whitespace, saving the values into an array
String[] singleLineVals = someLine.split("\\s+");
// Extract the first value
int firstValue = Integer.parseInt(singleLineVals[0]);
} catch (NumberFormatException nfe) {
// Handle the exception
}

How to fix while loop error login logout system (no database) (also is there a code about session time)?

I create a basic login and logout system (no database) with the only username given for my school homework, but I have problems with while loops and also session time.
I tried to copy and paste a group of codes to different parts of this main code so that I can get my expected outcome but it turns out to be a bit faulty. I tried to search on the internet about session time but I got nothing.
while (login = true){
try {
System.out.println("Enter your name:");
String name = cue.nextLine();
System.out.println("--------------------");
System.out.println("");
System.out.println("Date and Time of Login:");
System.out.println(dtf.format(now));
System.out.println("");
System.out.println("--------------------");
System.out.println();
System.out.println("Enter your name to log out:");
String logout = cue.nextLine();
System.out.println("");
if (logout.equals(name)){
System.out.println("--------------------");
System.out.println("");
System.out.println("Date and Time of Logout:");
System.out.println(dtf.format(now));
System.out.println("Session Time:");
/*can you also please tell me what code to tell the gap between the
login time and log out time?*/
System.out.println("");
System.out.println("--------------------");
login = false;
} else {
login = true;
}
} catch (Exception e){
cue.nextLine();
} finally{
System.out.println("Do you want to register again? 0 for yes and 1 for no");
int no = cue.nextInt();
if (no==0) {
login = true;
} else if (no==1) {
System.exit(1);
} else {
System.out.println("1 or 0 only!");
}
}
}
This must be the expected output:
if the name is correct:
Enter your name:
nmae
--------------------
Date and Time of login:
2019/02/03 16:38:46
--------------------
Enter your name to log out:
nmae
--------------------
Date and Time of logout:
2019/02/03 16:38:46
Session Time:
(This must show how many minutes and seconds a client uses the program)
--------------------
Do you want to register again? 0 for yes and 1 for no
0
Enter your name:
incorrect and it is corrected later on:
Enter your name:
name
--------------------
Date and Time of login:
2019/02/03 16:38:46
--------------------
Enter your name to log out:
nmae
Enter your name to log out:
name
but it turns out that on second loop, third loop and so on, the program asks me to "enter your name to log out" and "Do you want to register again? 0 for yes and 1 for no" instead. The "enter your name" part prints instead of asking my name.
and then when I enter 0 to exit, this error showed up C:\Users\DELL\AppData\Local\NetBeans\Cache\10.0\executor-snippets\run.xml:111: The following error occurred while executing this line:
C:\Users\DELL\AppData\Local\NetBeans\Cache\10.0\executor-snippets\run.xml:94: Java returned: 1
To get difference beetwen login time and logout time you can use Duration class from java8:
loginTime = LocalDateTime.now();
...
logoutTime = LocalDateTime.now();
Duration.between(loginTime, logoutTime).getSeconds();
You are returning an error level 1, which is the way a program terminates returning an error to the OS.
I can not test is as I do not use Windows, but you could try replacing System.exit(1) with System.exit(0).

How to take an input in asterix WHILE typing?

I have to create a login id which takes a password(in java) but I want the input to be in asterix while the user types to make it look professional. Is it even possible? Please give the syntax for the code to be input as asterix.
If the question has been asked before (i could not find it) please link before removing.
Thank You.
If you want to get password from console try the following:
Console console = System.console();
if (console == null) {
System.out.println("Couldn't get Console instance");
System.exit(0);
}
char passwordArray[] = console.readPassword("Enter your password: ");
console.printf("Password entered was: %s%n", new String(passwordArray));

Read tab delimited file and ignore empty space

I am working on a simple project in which a tab delimited text file is read into a program.
My problem:
When reading the text file there are regularly empty data spaces. This lack of data is causing an unexpected output. For lines that do not have data in the token[4] position all data read is ignored and "4" is displayed when I run a System.out.println(Just a test that the data is being read properly). When I incorporate a value in the token[4] position the data reads fine. It is not acceptable that I input a value in the token[4] position. See below for file and code.
2014 Employee Edward Rodrigo 6500
2014 Salesman Patricia Capola 5600 5000000
2014 Executive Suzy Allen 10000 55
2015 Executive James McHale 12500 49
2015 Employee Bernie Johnson 5500
2014 Salesman David Branch 6700 2000000
2015 Salesman Jonathan Stein 4600 300000
2014 Executive Michael Largo 17000 50
2015 Employee Kevin Bolden 9200
2015 Employee Thomas Sullivan 6250
My code is:
// Imports are here
import java.io.*;
import java.util.*;
public class EmployeeData {
public static void main(String[] args) throws IOException {
// Initialize variables
String FILE = "employees.txt"; // Constant for file name to be read
ArrayList<Employee> emp2014; // Array list for 2014 employees
ArrayList<Employee> emp2015; // Array list for 2015 employees
Scanner scan;
// Try statement for error handling
try {
scan = new Scanner(new BufferedReader(new FileReader(FILE)));
emp2014 = new ArrayList();
emp2015 = new ArrayList();
// While loop to read FILE
while (scan.hasNextLine()) {
String l = scan.nextLine();
String[] token = l.split("\t");
try {
String year = token[0];
String type = token[1];
String name = token[2];
String monthly = token[3];
String bonus = token[4];
System.out.println(year + " " + type + " " + name + " " + monthly + " " + bonus);
} catch (Exception a) {
System.out.println(a.getMessage());
}
}
} catch(Exception b) {
System.out.println(b.getMessage());
}
}
}
The output I receive for lines with "Employee" returns in an unexpected way.
Output:
run:
4
2014 Salesman Patricia Capola 5600 5000000
2014 Executive Suzy Allen 10000 55
2015 Executive James McHale 12500 49
4
2014 Salesman David Branch 6700 2000000
2015 Salesman Jonathan Stein 4600 300000
2014 Executive Michael Largo 17000 50
4
4
BUILD SUCCESSFUL (total time: 0 seconds)
I tried to use an if-then to test for null value in token[4] position but that didn't really help me. I've done quite a bit of searching with no success.
I am still very new to the programming world, so please pardon my coding inefficiencies. Any support and general feedback to improve my skills is greatly appreciated!
Thank you,
Bryan
Java Devil is right that the underlying issue because of an ArrayOutOfBoundsException. But it's also worth exploring why you didn't see that. As we discussed in the comments your "Try statement for error handling" is in fact not handling your errors at all, instead it is suppressing them, which is generally a poor plan as it allows your program to continue running even after your assumption (that it works correctly) has been violated.
Here's a slightly cleaned up version of your code. The underlying problem that causes the ArrayOutOfBoundsException is still there, but the issue would be immediately apparent if you'd structured your code this way instead. There's a few comments calling out issues inline.
public class EmployeeData {
// constants should be declared static and final, and not inside main
private static final String FILE = "employees.txt";
// If you have an exception and you don't know how to handle it the best thing
// to do is throw it higher and let the caller of your method decide what to do.
// If there's *nothing* you want to do with an exception allow main() to throw
// it as you do here; your program will crash, but that's a good thing!
public static void main(String[] args) throws IOException {
// Notice the <> after ArrayList - without it you're defining a "raw type"
// which is bad - https://stackoverflow.com/q/2770321/113632
ArrayList<Employee> emp2014 = new ArrayList<>();
ArrayList<Employee> emp2015 = new ArrayList<>();
// A try-with-resources block automatically closes the file once you exit the block
// https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
try (Scanner scan = new Scanner(new BufferedReader(new FileReader(FILE)))) {
while (scan.hasNextLine()) {
String l = scan.nextLine();
String[] token = l.split("\t");
// The code below this line assumes that token has at least five indicies;
// since that isn't always true you need to handle that edge case before
// accessing the array indicies directly.
String year = token[0];
String type = token[1];
String name = token[2];
String monthly = token[3];
String bonus = token[4];
System.out.println(year + " " + type + " " + name + " " + monthly + " " + bonus);
}
}
}
}
This is happening because you are actually getting an ArrayOutOfBoundsException and the message for that is '4'. Because the index of 4 is greater than the length of the array. You should put in your catch statement b.printStackTrace() as this will give you greater details when ever the caught exception occurs.
You can get around this by adding the following:
String bonus = "";
if(token.length > 4)
bonus = token[4];

Java: populating Scanner with default value on Scanner.nextLine();

I am writing a java program that runs a loop and keeps asking the user for input. The program then does a bunch of things with the string, and asks for another string and repeats.
The issue is that many strings are very similar, so i would like to populate the prompt with the input from the last time in the loop. For instance: If the user enters a value as follows:
Enter the SKU Number: APE-6603/A
... Then the next time it asks for an SKU, it will wait till the user presses enter as normal, but be ready with the last value before the user even types anything:
Enter the SKU Number: APE-6603/A
... And the user can make simple changes very fast like replace the /A with /B and press enter! If the string that holds the user input is called "lookFor", is there a way to populate the prompt with this value in Java? It would be VERY useful!
Thanks!
After discussing this idea with a few people, it seems that what i want is not possible. The way of input is too simple to allow something like this.
My only possible solutions involve not running this from my IDE. I can either elect to use my application, or change the application into a GUI based applet. Running from the console will open up the "Press up" option, as suggested by rchirino, and using a GUI would let the value entered sit there for editing later.
If anyone is looking to do what i posted above, the answer is "Java cant do it!". Sorry. :)
You might want to try something like this:
public String promptandgetWithShowDefault(String prompt, String supplied) {
String prmpt = prompt + " (press Enter for \"" + supplied + "\"):";
String tmpch = null;
System.out.print(prmpt);
tmpch = scanner.nextLine().trim();
if (tmpch == null || tmpch.equals("")) {
return supplied;
} else {
return tmpch;
}
}
If the goal is to get a simple binar answer from the user like:
Would you like to do that? ( y / n ) y
then the empty string returned by the user, in the answer from Dmv, will do the trick, except that when the user types "n" or attempts to delete the trailing "y", it won't disappear, so it would then be clearer to write the prompt like:
Would you like to do that? ( [ y ] / n )
But when the goal is to get a long string, like the original question or a file path for instance, that the user can edit to correct a typo or not to overwrite previous file .... then you definitely need something else which doesn't seem to be available in Java.
Well do it in C then!!! with the help of libreadline...
it's probably possible, easier and more portable to do the same trick in Python, but I have no idea how to code in Python.
Here is a simple Java MRE to illustrate it:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
public class Main
{
public static void main(String[] args)
{
String path = System.getProperty("user.home") + File.separatorChar + "Documents";
File file = null;
do {
path = askForString("Enter the filepath to open:", path );
if ( ( path == null) || ( path.isBlank())) break;
file = new File( path );
} while ( ! file.exists() );
System.out.println("Openning " + path + "....");
// ......
}
public static String askForString( String message, String defaultString)
{
String response = null;
System.out.println( message);
// any extra String in cmd[] will be added in readline history
String[] cmd = { "/path/to/executable/ask4stringWdefault", defaultString};
try
{
ProcessBuilder pb = new ProcessBuilder(cmd);
// Make sure the subprocess can print on console and capture keyboard events
pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process p = pb.start();
BufferedReader stderrBuffer = new BufferedReader(new InputStreamReader(p.getErrorStream()));
int retcode= p.waitFor();
if ( retcode != 0)
{
System.err.println("The process terminated with error code: " + retcode + "\n" + stderrBuffer.readLine());
return null;
}
response = stderrBuffer.readLine();
} catch( Exception e) {
e.printStackTrace();
}
return response;
}
}
To build the executable "ask4stringWdefault" you need first to get the GNU Readline Library utility and compile it, ideally cross-compile for any platform Java supports, to get a static library that you will link while compiling ( or cross-compiling ) the following C script:
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
const char *defstr;
int prefill(const char *txt, int i);
int main(int argc, const char * argv[])
{
if ( argc < 2)
{
fprintf(stderr, "You must provide a default value\n");
return -1;
} else if ( argc > 2) {
// * optional extra values can be passed to populate history * //
if ( argc > 255) argc = 255;
for ( unsigned char i=0; i < argc; i++)
{
add_history(argv[i]);
}
}
defstr = argv[1];
char *cbuffer;
rl_startup_hook = prefill;
if ((cbuffer = readline(NULL)) == NULL) /* if the user sends EOF, readline will return NULL */
return 1;
fprintf( stderr, "%s\n", cbuffer);
free(cbuffer);
return 0;
}
int prefill(const char *t, int i)
{
rl_insert_text(defstr);
return 0;
}
The result is printed on stderr as it is the only stream that Java can keep track of, stdout and stdin being under the control of the executable subprocess itself.
It works fine on a Mac with arm64 architecture, using Eclipse you can't actually edit the default provided, any character typed at the prompt will be append to default string, but just hitting return will send unchanged default value back, which can be enough for basic testing.
I think I understand what you want to do, but it's rather simple. If your program is a console application (command-line), which I'll assume, then you just need to press the UP key to populate the prompt with the last typed characters.
If you're working with GUI elements then you can check the API documentation for the particular class of object you're using and check out it's fields.
Hope this helps!

Categories