I'm still very new to java and I'm working on a school assignment that's working on cryptography. When I was searching for methods to read from files I saw many had a try and catch block. I'm not very familiar with the use of these and I want to try and avoid using them in my code but when I remove them I have two exceptions reported at the new in new FileReader and at the bracket after reader.readLine(). But if I do use them it works relatively well. Can anyone explain what is happening? Also when using the catch and try I get an exception Null when my encoding is done. Any help is appreciated.
import java.io.*;
import java.util.*;
public class Encrypter {
public static void main(String[] args) {
File input = null;
if (1 < args.length) {
input = new File(args[1]);
} else {
System.err.println("Invalid arguments count:" + args.length);
System.exit(0);
}
String key = args[0];
BufferedReader reader = null;
try {
int i = 0;
String[] inputText = new String[20];
String[] encryptText = new String[20];
reader = new BufferedReader(new FileReader(input));
while ((inputText[i] = reader.readLine()) != null) {
encryptText[i] = inputText[i];
System.out.println(inputText[i]);
++i;
}
int hash = key.hashCode();
Random random = new Random(hash);
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
String alphabetPerm = alphabet;
char temp;
for (int j = 0; j < 100; j++) {
int n1 = random.nextInt(27) + 0;
int n2 = random.nextInt(27) + 0;
char[] swapper = alphabet.toCharArray();
temp = swapper[n1];
swapper[n1] = swapper[n2];
swapper[n2] = temp;
String alphaSwap = new String(swapper);
alphabet = alphaSwap;
}
System.out.println(alphabet);
for (int k = 0; k < inputText.length; k++) {
encryptText[k] = inputText[k].replaceAll("[^A-Za-z0-9 ]+", " ");
for (int j = 0; j < inputText[k].length(); j++) {
int index = alphabetPerm.indexOf(encryptText[k].charAt(j));
encryptText[k] = alphabetSwapper(encryptText[k], alphabet, index, j);
System.out.println(encryptText[k]);
}
}
} catch (Exception e) {
System.err.println("Caught Exception: " + e.getMessage());
}
}
public static String alphabetSwapper(String s, String alpha, int index, int value) {
char toSwap = s.charAt(value);
char[] inputChars = s.toCharArray();
inputChars[value] = alpha.charAt(index);
String swapped = new String(inputChars);
return swapped;
}
}
You are better off not catching the exception the way you are because you are discarding the two most useful pieces of information, which exception was thrown and where did it happen.
Instead of catching the exception, you can add the exceptions to the throws clause of main()
e.g.
public static void main(String[] args) throws IOException {
// ...
}
Can anyone explain what is happening?
When you read a file you might be an IOException e.g. if the file is not present. You might have to catch this exception but for now you can let the caller to main print it out if it happens.
Also when using the catch and try I get an exception Null when my encoding is done
This means you are triggering an exception without a message. If you print the exception and where it happened(or let the JVM do it for you) you will see where.
To determine why this is happening I suggest stepping through the code in your debugger so you can understand what each line does.
A main method of the form as you pasted is usually the entry point of a program and not called by other java code. So it is good practise to catch and handle all Exceptions before leaving your program.
'Handle' can mean different things:
Simply print the message of the exception to the console as you do (in that case you loose information as Peter Lawrey already pointed out).
Print the stacktrace (e.printStackStrace()) which outputs more information about the exception on the stderr output. This is what java does if the main() method is left with an uncaught exception.
If using a logger framework: Loggers and its Appenders are able to print all exception information into a destination of your choice.
Handle it (1-3) and exit java with an exit code != 0 in order that a (programmatical) caller of your application can handle the error situation.
BTW1: I even would catch Throwable. So you also catch possible unchecked exceptions (NullPointerException, ArrayIndexOutOfBoundsException, etc.). And place the try at the very beginning (if you make an error in accessing your args array you would have covered also the ArrayIndexOutOfBoundsException)
BTW2: If you would not have any try..catch in the main method I assume the code would not even compile because the compiler can detect that there might be unhandled checked exceptions (from your IO operations).
Related
I have a java program that reads from a cvs file that looks like this:
1111,John,23
2222,Mary,32
...
I want to store each field in an array. Whenever I run the following program I get the following message:
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:862)
at java.util.Scanner.next(Scanner.java:1485)
at java.util.Scanner.nextInt(Scanner.java:2117)
at java.util.Scanner.nextInt(Scanner.java:2076)
How can I deal with that exception? I guess it is because scanner reads beyond its limit, however, doesn't the while block ensure that it will read within its limits?
Any help is appreciated
import java.util.*;
import java.io.*;
public class program
{
public static void main(String[] args) throws FileNotFoundException, IOException
{
BufferedReader br = new BufferedReader(new FileReader("info.csv"));
int[] ids = new int[20];
String[] names = new String[20];
int[] age = new int[20];
String line;
int i = 0;
while( (line = br.readLine()) != null)
{
Scanner s = new Scanner(line).useDelimiter(",");
ids[i] = s.nextInt();
names[i] = s.next();
sales[i] = s.nextInt();
s.close();
i++;
}
for(int j = 0; j < 20; j++)
{
System.out.println("Id: "+ids[i]+" Name: "+names[i]+" Age: "+ age[i]);
}
}
}
Reading CSV files is actually quite complicated. Handling quotes and newlines is quite difficult. There are also encoding issues to consider (which you haven't; you should basically never use this constructor FileReader, as it uses 'platform default encoding'). Don't reinvent this wheel; use something like super-csv.
The while block ensures you read each line once and don't read beyond the end of the file. Per line you forcibly go: an int, a string, and an int, period. That's where the crash occurs. Mostly likely there's a trailing newline at the end of the file or some such. A trivial example would be to check if line.trim() is empty, and if so, to just move on (continue;) and not attempt to read the line.
But, really, don't handroll this, get a CSV parser.
NB: If you must reinvent this wheel, there are far nicer and easier ways to get all lines from a file. For example, Files.newBufferedReader(Paths.get("/path/to/whatsit")) or even Files.lines(Paths.get("/path/to/whatsit")), conveniently those methods also default to UTF-8, i.e. a consistent choice instead of 'flip a coin and pray'.
Try to use split(,)
String[] split = line.split(",");
if (split.length >= 0) {
String input = split[0];
if (input.matches("[0-9]+"))
ids[i] = Integer.parseInt(input);
}
if (split.length >= 1) {
names[i] = split[1];
}
if (split.length >= 2) {
String input = split[2];
if (input.matches("[0-9]+"))
ids[i] = Integer.parseInt(input);
}
I'm building a small application in Java, small game mechanics but nothing serious. I have a class which purpose is to fetch data from a file. But when I declare the two classes to read from it the program justs ignore everything and continues. As a result, when I try to access the respective lists it gives me null pointer exception. Code of the method that fetches data below:
public void getData(int l, player tmp, level le) {
String[] dataPlayer;
String[] dataLevel;
try {
//FileReader f = new FileReader(this.levelPath.concat(Integer.toString(l)));
File f = new File(this.levelPath.concat(Integer.toString(l)));
BufferedReader buff = new BufferedReader(new FileReader(f));
System.out.println("Reached");
boolean eof = false;
while (!eof) {
String b = buff.readLine();
if (b == null)
eof = true;
else {
if (b.contains("player")) {
dataPlayer = b.split("-");
for (int i = 0; i < dataPlayer.length; i++) {
if (i == 0)
continue;
items it = new items(dataPlayer[i]);
tmp.setInventory1(it);
}
}else if (b.contains("level")) {
dataLevel = b.split("-");
for (int i = 0; i < dataLevel.length; i++) {
if (i == 0)
continue;
items it = new items(dataLevel[i]);
le.setSpecific(it);
}
}
}
}
}catch (IOException i) {
i.getMessage();
}
}
File contents of the file "levelData1":
player-hat
player-flashlight
level-flower
level-rock
player-adz
The problem with this particular problem was the path, it needed the absolute like that /home/toomlg4u/IdeaProjects/javaProject/src/Data/levelData.
You're doing a lot of things inside that try/catch that may not throw an IOException. If you get any other exception, it's not going to be caught. Depending on what other exception handling you have in place, that may cause weird behavior. For debugging, you could catch all exceptions, and see if you're getting something else.
If you want to remain to your loop code then you can refactor your code to look like this one:
public void getData(int l, player tmp, level le) {
try (BufferedReader buff = new BufferedReader(new FileReader(new File(this.levelPath + l)))) {
String b;
while ((b = buff.readLine()) != null) {
if (b.contains("player")) {
String[] dataPlayer = b.split("-");
items it = new items(dataPlayer[1]); //because you know that you will have an array with only 2 elements
tmp.setInventory1(it);
}else if (b.contains("level")) {
String[] dataLevel = b.split("-");
items it = new items(dataLevel[1]); //because you know that you will have an array with only 2 elements
le.setSpecific(it);
}
}
}catch (IOException e) {
e.printStackTrace();
}
}
It is a little bit better than that you have, easier to debug and to read. I advice you to read about try with resources.
As a rule of thumb, each time when you open a stream you have to close it. When you don't open it yourself then don't close it.
This is how it should look like a decent program in Java:
private Stream<Items> asStreamOfItems(String line){
return Stream.of(line.split("-")).skip(1).map(Items::new);
}
public void parseFile(String pathToTheFile) throws IOException {
List<String> lines = Files.readAllLines(Paths.get(pathToTheFile));
List<Items> players = lines.stream().filter(line -> line.contains("player")).flatMap(this::asStreamOfItems).collect(Collectors.toList());
List<Items> levels = lines.stream().filter(line -> line.contains("level")).flatMap(this::asStreamOfItems).collect(Collectors.toList());
........
}
In this case all your weird errors will vanish.
After you edited the post I saw your file content. In this case the code should look like this one:
class Items {
private final String name;
public Items(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static Items parse(String line) {
return new Items(line.split("-")[1]);
}
}
public void parseFile(String pathToTheFile) throws IOException {
List<String> lines = Files.readAllLines(Paths.get(pathToTheFile));
List<Items> players = lines.stream().filter(line -> line.contains("player")).map(Items::parse).collect(Collectors.toList());
List<Items> levels = lines.stream().filter(line -> line.contains("level")).map(Items::parse).collect(Collectors.toList());
..............
}
Btw, you broke a lot of Java and general programming rules like:
using continue is a bad practice. It should be used only in extreme cases because it makes the code difficult to read.
the class name in Java should be in the CamelCase notation
one method should have only one responsibility
DON'T mutate the object inside of a method (example: tmp.setInventory1(it);) very very very bad practice
when you work with streams use try with resource or try/catch/finally to close your stream after you finish the reading.
Before jumping to write code explore the JAVA IO SDK to look for better methods to read from files
I have the following code snippet from my tester class.
FileReader freader=new FileReader(filename);
BufferedReader inputFile=new BufferedReader(freader);
int numScores = 0;
String playerType = "";
String nameHome = "";
String playerName = "";
String home = "";
String location = "";
int score = 0;
String date = "";
double courseRating = 0;
int courseSlope = 0;
ArrayList<Player> players = new ArrayList<Player>();
while (inputFile.read()!= -1) {
numScores = Integer.parseInt(inputFile.readLine());
playerType = inputFile.readLine();
nameHome = inputFile.readLine();
StringTokenizer st = new StringTokenizer(nameHome,",");
playerName = st.nextToken();
home = st.nextToken();
The program compiles, however when the tester is run, I get the following output error.
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:592)
at java.lang.Integer.parseInt(Integer.java:615)
at PlayerTest.main(PlayerTest.java:34)
I've tried researching this and what I fould was there's possibly a space when it changes the String that is read from the data file and converts it to an int. I tried reading directly into a strin, trimming the string, then converting to the int, but it got the same error.
This was the code that replaced numScores = Integer.parseInt(inputFile.readLine());
tempScores = inputFile.readLine();
tempScores.trim();
System.out.println(tempScores);
numScores = Integer.parseInt(tempScores);
Any help is appreciated.
*edited to show sample data
Sample data from file
3
B
James Smith, Strikers
FWB Bowling, 112,09/22/2012
White Sands, 142,09/24/2012
Cordova Lanes,203,09/24/2012
Possibly, your File contains empty lines. These are read as "" and therefore cannot be converted to int.
Furthermore, it is possible that you read the first character of each line by the read-statement in the header of the while-loop, so that it is ignored in the readline command. Then a number of length 1 (like "1") would become an empty line.
In any case, the construction of your loop is a bug.
You can put it all in an if statement:
if(!tempScores.equalsIgnoreCase(""))
{
I ran into a similar issue today. I was reading a response from REST end point and try to parse the json response. Bam! hit an error. Later on I realize the file had a BOM.
My suggestion is create a var
String var = inputFile.readLine();
int numScores = Integer.parseInt(var);
add a breakpoint and inspect what var contains, in my case the response had a BOM an empty unicode character code 65279 / 0xfeff. In any debugger worth it's salt you should be able to see each character.
if it's the case you need to strip that value from the string.
I used this library to detect this issue org.yaml:snakeyaml:1.16
import org.yaml.snakeyaml.reader.UnicodeReader;
//more code
private String readStream(InputStream inputStream) throws IOException {
UnicodeReader unicodeReader = new UnicodeReader(inputStream);
char[] charBuffer = new char[BUFFER_SIZE];
int read;
StringBuilder buffer = new StringBuilder(BUFFER_SIZE);
while ((read = unicodeReader.read(charBuffer,0,BUFFER_SIZE)) != -1) {
buffer.append(charBuffer, 0, read);
}
return buffer.toString();
}
You need to understand this please look into it.
Basic understanding is
try {
//Something that can throw an exception.
} catch (Exception e) {
// To do whatever when the exception is caught.
}
There is also an finally block which will always be execute even if there is an error. it is used like this
try {
//Something that can throw an exception.
} catch (Exception e) {
// To do whatever when the exception is caught & the returned.
} finally {
// This will always execute if there is an exception or no exception.
}
In your particular case you can have the following exceptions (link).
InputMismatchException - if the next token does not match the Integer regular expression, or is out of range
NoSuchElementException - if input is exhausted
IllegalStateException - if this scanner is closed
So you would need to catch exceptions like
try {
rows=scan.nextInt();
} catch (InputMismatchException e) {
// When the InputMismatchException is caught.
System.out.println("The next token does not match the Integer regular expression, or is out of range");
} catch (NoSuchElementException e) {
// When the NoSuchElementException is caught.
System.out.println("Input is exhausted");
} catch (IllegalStateException e) {
// When the IllegalStateException is caught.
System.out.println("Scanner is close");
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 7 years ago.
My code is supposed to read a file line by line, to put each one in a string array named: tuples, (tuples=ligne.split(" "); ) and then add this tuples to an arraylist, one line read = one element of the arraylist.
Unfortunately, my code doesn't work! My buffered reader throws a NullPointerException in my loop!
Error returned in the ExtractFile() method, line 120: tuples= ligne.split(" ");
File file = new File("Department.txt");
BufferedReader in;
PrintWriter out;
String ligne;
int nbCols; //number of metadatas in my file.txt
String metadata[] = new String[nbCols];
String[] tuples = new String[nbCols];//1ere case indique num ligne
ArrayList<String[]> itemset = new ArrayList<String[]>();
public ArrayList ExtractionFile () {
try {
int i = 1;
in = new BufferedReader(new FileReader(file));
while ((ligne = in.readLine()) != null) {
while (ligne.charAt(0) != '1') {
ligne = in.readLine();//browse until line 1 is found
}
tuples = ligne.split(" ");
itemset.add(tuples);
System.out.println(Arrays.toString(itemset.get(0)));
for (i = 2; i < TuplesCount(); i++) {
ligne = in.readLine();
tuples = ligne.split(" ");// THIS LINE THROWS THE EXCEPTION
itemset.add(tuples);
System.out.println(Arrays.toString(itemset.get(i)));
}
}
} catch (IOException es) {
es.printStackTrace();
} catch (ArrayIndexOutOfBoundsException exepti) {
exepti.printStackTrace();
}
return itemset;
}
A NullpointerException tells you that your code
attempts to use null in a case where an object is required. These include:
Calling the instance method of a null object.
...
In your case, you've told us that the error occurs on
tuples = ligne.split(" ");
You're trying to call split on ligne and - given the documentation quote above - that implies that ligne is null at that point.
It's worth noting that it is the second occurence of that line that throws the Exception, so it is not as simple as the file not having a line that starts with 1
Why?
You need to use a debugger or use lots of System.out.println to convince yourself how the value of ligne changes as your code executes and, crucially, where it becomes null.
In your case - we don't know what TuplesCount() returns, but the likelihood is that you keep iterating in that loop beyond the end of the file, so the line immediately before the one that fails
ligne = in.readline();
can return null and you never check for that at that point. Note that conditions for the loops are only checked after each iteration of the loop - so , except for the one right at the top in the condition of the while loop, all the calls to ligne = in.readline(); could return null and are never checked.
The code you provide us is really unreadable and should be formatted to easy debug it. Instead, you can try this simple code that i have tested on my IDE
package example;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
public class FileSplit {
public static void main(String[] args) {
ArrayList<String[]> phrases = new ArrayList<String[]>();
try{
BufferedReader in = new BufferedReader(new FileReader("Department.txt"));
String s;
while((s = in.readLine()) != null){
String[] words = s.split(" ");
phrases.add(words);
}
}catch(Exception e){
e.printStackTrace();
}
for(int i=0;i<phrases.size();i++){
for(int j=0;j<phrases.get(i).length;j++)
System.out.println(phrases.get(i)[j]);
}
}
}
Are you testing this with a file which doesn't contain a line 1? If so, you run this it will keep executing the inner loop despite the fact that the value is null, resulting in an exception the time after the last line has been read. To fix this change the inner loop to be an if.
Like so:
public ArrayList ExtractionFile() {
try {
int i = 1;
in = new BufferedReader(new FileReader(file));
ligne = in.readLine(); //It can be more readable to seperate the assignment and the condtion
while (ligne != null) {
if (ligne.charAt(0) != '1') {
ligne = in.readLine();//browse until line 1 is found
} else {
tuples = ligne.split(" ");
itemset.add(tuples);
System.out.println(Arrays.toString(itemset.get(0)));
for (i = 2; i < TuplesCount(); i++) {
ligne = in.readLine();
tuples = ligne.split(" ");// CETTE LIGNE SOULEVE L EXCEPTION
itemset.add(tuples);
System.out.println(Arrays.toString(itemset.get(i)));
}
}
}
} catch (IOException es) {
es.printStackTrace();
} catch (ArrayIndexOutOfBoundsException exepti) {
exepti.printStackTrace();
}
return itemset;
}
private int TuplesCount() {
return Arrays.asList(tuples).size();
}
public static void main(String[] args){
Main main = new Main();
main.ExtractionFile();
}
}
As per some of the points above, please do format your code - it makes it easier to get help! Also, read up on breakpoints!
I am getting an unreported exception; must be caught or declared to be thrown error in the fill method below. From similar posts I read I am assuming that the error originates since the read method has throws Exception but I cannot fix it.
public void read(int fileName) throws Exception
{
FileInputStream in = null;
try
{
Scanner in = new Scanner("dataset.txt");
File inFile = new File(in.nextLine());
in = new FileInputStream(inFile);
}
catch ( Exception e)
{
System.out.println(e);
}
BufferedReader buf = new BufferedReader(new InputStreamReader(in) );
String input;
input = buf.readLine();
fill(input,buf);
}
where fill is defined as:
public void fill(String in,BufferedReader buf)
{
StringTokenizer token = new StringTokenizer(input);
no = token.countTokens();
constraints = new Vector[noOfAttributes];
for (int i=0; i < no; i++)
{
c[i] = new Vector();
names = new String[noOfAttributes];
}
for (int i=0; i < no; i++)
{
names[i] = token.nextToken();
}
while((in = buf.readLine()) != null) //<----error given here
{
token = new StringTokenizer(input);
Train example = new Train(no);
}
buffer.close();
}
Your fillData calls buffer.readLine(), which is declared to throw IOException - but you neither catch the exception witin fillData, nor declare that it might be thrown.
The simplest fix is to change the signature of fillData to:
public void fillData(String input, BufferedReader buffer) throws IOException
I would also strongly recommend not closing the reader within fillData. Usually, the same code that acquires a resource should be responsible for closing it. A try-with-resources statement is most appropriate here, so in read:
try (BufferedReader buffer = new BufferedReader(new InputStreamReader(in))) {
String input = buffer.readLine();
fillData(input,buffer);
}
Even this isn't ideal, however - because you're opening the input stream earlier on. I'd also recommend always passing an encoding to the InputStreamReader constructor, otherwise it will use the platform default encoding. In Java 7+ you can use Files.newBufferedReader which defaults to UTF-8.
Additionally:
read declaring that it throws Exception is generally a bad idea; only throw specific exceptions
Catching Exception in read is a bad idea; only catch specific exceptions
Continuing in read after a failure is a bad idea - in will be null, causing a failure immediately afterwards
It's very bizarre to have a parameter called fileName of type int. As it happens, you're not using that anyway - what's the point of it?
Basically all of your exception handling and resource management needs a fair amount of work.