ArrayIndexOutOfBounds Exception, but not out of bounds? - java

I'm writing a method that edits a record in a CSV file, which should print everything except for the line im editing, then print the edited version onto a new file.
while((line = br.readLine()) != null) {
if(line.contains("PATRON")) {
pw.println(line);
}
if(!line.contains("PATRON")) {
String[] str = line.split(",", 7);
if(str[1].equals(ID)) {
pw.println(str[0] + "," + ID + "," + str[2] + "," + "false" + "," + "0" + "," + str[5] + "," + "0");
}else {
pw.println(line);
}
}
}
When i try to run this and enter a valid ID, it gives me this exception
java.lang.ArrayIndexOutOfBoundsException: 1
at myproject.Materials.returnmat(Materials.java:296)
at myproject.Library.mmenu(Library.java:121)
at myproject.Library.mainmenu(Library.java:143)
at myproject.Library.main(Library.java:11)
However after running some tests,
for(int x=0;x<str.length;x++) {
System.out.println(x+ ": " +str[x]);
}
It outputs exactly what id expect, 1: 101, 1:102, etc..
So this shows me that the ID is definitely at the str[1] index.
Why is it throwing me the exception?
EDIT: If its relevant, here's how im calling it.
case "7":
System.out.println("Enter material ID: ");
String matsid = scan.nextLine();
mats.returnmat(matsid);
scan.nextLine();
break;

Check your string length before doing if(str[1].equals(ID)) {
Something like :
if(str.length<1) {
System.out.println("line no good="+line);
} else ...
It's likely you have a bad line in the CSV or maybe this is the last blank line.

Here
String[] str = line.split(",", 7);
if(str[1].equals(ID)) {
the splitting line must have had return array of length=1 thus maximum index would be 0 - but you are exceeding it using str[1];

Related

How to correctly split new line in text file (Java)?

I need a quick help with my code. I think it all works fine, but I have just one problem. I need to split every line of text file and add each of them to array. This assignment is about using RandomAccessFile class. And problem is - I can't split these lines from text file. It only says that each array is null.
I was typing any regex that I found online into String.split. Nothing works. I was also trying to use Scanner, but it went much worse.
try(RandomAccessFile raf = new RandomAccessFile("domy.txt", "rw")){
while((str = raf.readLine()) != null){
String[] data = new String[100];
data = str.split("\n");
String name = data[0];
String floors = data[1];
String price = data[2];
String location = data[3];
System.out.println(data[0] + " " + data[1] + " " + data[2] + " " + data[3]);
if(floors.equals("1") && location.equals("Wies")){
var floorsInt = Integer.parseInt(floors);
var priceDouble = Double.parseDouble(price);
raf.seek(raf.getFilePointer() - str.length());
raf.writeBytes(name + "\n" + floorsInt + "\n" + df.format(priceDouble * 0.9) + "\n" + location);
}
}
}
catch(FileNotFoundException e){
e.printStackTrace();
The most common errors are "Index 1 out of bounds for length 1" and "floors is empty"
Willa
3
1000000.00
Miasto
Chata
1
99999.99
Wies
Here is what I have in a text file

NumberFormatException when attempting to Tokenize a String

I'm trying to tokenize a String and save it to a binary file, but when I run the program, I get a NumberFormatException. Here is my stack trace:
Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: " 1"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:481)
at java.lang.Integer.parseInt(Integer.java:527)
at Project6.saveBSAFile(Project6.java:187)
Here is my code, which is trying to tokenize a String and save it to a binary file:
public void saveBSAFile() throws FileNotFoundException, IOException
{
jfc.setDialogTitle("Specify a file to save");
int userSelection = jfc.showSaveDialog(this);
if (userSelection == jfc.APPROVE_OPTION)
{
File filename = jfc.getSelectedFile();
JOptionPane.showMessageDialog(null, "File to save " + filename,
"Save Review", JOptionPane.INFORMATION_MESSAGE);
FileOutputStream FOStream1 = new FileOutputStream(filename, true);
DataOutputStream DOStream1 = new DataOutputStream(FOStream1);
}
else if (userSelection == jfc.CANCEL_OPTION)
{
return;
}
int index = 0;
while (tools.getNumberOfItems() <= 10 && processRec.getToolRecords(index) != null)
{
StringTokenizer tokens = new StringTokenizer(processRec.getToolRecords(index), "|:");
toolStrTok = tokens.nextToken();
toolNameTok = tokens.nextToken();
idStrTok = tokens.nextToken();
idTok = tokens.nextToken();
qualStrTok = tokens.nextToken();
qualTok = tokens.nextToken();
stockStrTok = tokens.nextToken();
stockTok = tokens.nextToken();
priceStrTok = tokens.nextToken();
priceTok = tokens.nextToken();
idTok.trim();
qualTok.trim();
stockTok.trim();
priceTok.trim();
id = Integer.parseInt(idTok);
quality = Integer.parseInt(qualTok);
numInStock = Integer.parseInt(stockTok);
price = Double.parseDouble(priceTok);
FileOutputStream FOStream2 = new FileOutputStream(filename, true);
DataOutputStream DOStream2 = new DataOutputStream(FOStream2);
DOStream2.writeUTF(toolStrTok);
DOStream2.writeUTF(" " + toolNameTok);
DOStream2.writeUTF(" " + idStrTok + " ");
DOStream2.writeInt(id);
DOStream2.writeUTF(" " + qualStrTok + " ");
DOStream2.writeInt(quality);
DOStream2.writeUTF(" " + stockStrTok + " ");
DOStream2.writeInt(numInStock);
DOStream2.writeUTF(" " + priceStrTok + " ");
DOStream2.writeDouble(price);
DOStream2.close();
index++;
}//end loop
}//end saveBSAFile
And here is the String i'm attempting to tokenize, which is being pulled from a method in another class file(which is being referenced by a call to processRec):
public String getRecord(int index)
{
return "Tool Name: " + toolArray[index].getName()
+ "| Tool ID: " + toolArray[index].getToolID()
+ "| Tool Quality: " + toolArray[index].getQuality()
+ "| Number in Stock: " + toolArray[index].getNumberInStock()
+ "| Tool Price: " + toolArray[index].getPrice();
}//end getRecord
I've tried a few different things, such as trimming the Strings using trim() i'm attempting to tokenize, but that didnt seem to work :( I also tried reworking the code a bit but that hasn't netted me much luck, either. I'm very much a novice when it comes to exceptions and stack traces, so I was hoping someone may be able to point out any obvious(or not so obvious) mistakes I may be making. Thanks so much in advance :)
The trim() method doesn't change the original String; it's immutable.
Returns a string whose value is this string, with any leading and trailing whitespace removed.
(emphasis mine)
The trim method returns the trimmed String, but you discard the returned String. idTok is still " 1", with spaces.
Change
idTok.trim();
to
idTok = idTok.trim();
and likewise with the other tokens. Then parseInt will see the trimmed string (e.g. "1") and parse the integers correctly.

How to only add something to a string if it doesn't contain it?

I am making a Lipogram program where any words with the banned letter are printed, however, the words are sometimes printed twice. How do I get it to not repeat the words?
Here is my code:
public String allWordsWith(char letter) {
String str = "";
String word = "";
s = s.replace(".", " ");
s = s.replace(",", " ");
s = s.replace("?", " ");
s = s.replace("!", " ");
s = " " + s + " ";
for (int i = 0; i <= s.lastIndexOf(letter); i++) {
if (s.charAt(i) == letter) {
if (str.contains(s.substring(s.lastIndexOf(" ", i), s.lastIndexOf(" ", i) + 1) + '\n') == true) {
} else {
word += s.substring(s.lastIndexOf(" ", i), s.indexOf(" ", i)) + '\n';
str += word;
}
}
}
return str;
}
Important clarification: Is the function run with the letter chosen as "o" on the string "hello hi hello howdy" meant to return "hello hello howdy" or "hello howdy". I.e., if the word appears twice, do you want to print it twice, or do you only want to print it once regardless of repetition?
If only once regardless of repetition, then you should be using a Set to store your data.
However, I think there's a chance you're instead dealing with an issue that when running the function with the letter chosen as "l" on that same string, "hello hi hello howdy", you are getting an output of "hello hello hello hello". Correct?
The issue here is that you are checking every letter and not testing each word. To fix this, I would use:
String[] words = s.split(" ");
to create an array of your words. Test each value in that array to see if it contains the given letter using:
if(words[index].contains(letter)){
str += " " + words[index];
}

How to use StringBuilder properly instead of an excessively long method

I'm wondering how I can use the StringBuilder properly because my current method (http://pastebin.com/VHjM0KeQ) is way too long, I'm sure I can do a loop or a string builder I'm just not sure how to, thanks.
As everything but the case for 0 arguments and for more then 20 arguments is pretty much the same you can easily use a StringBuilder along with a loop to add your words to the text.
Like this:
if (args.length == 0) {
player.sendMessage(ChatColor.DARK_RED + "Usage: /pm <Target> <Message>");
} else if (args.length > 20) {
player.sendMessage(ChatColor.DARK_RED + "Error: Maximum of 20 words.");
} else {
StringBuilder sb = new StringBuilder();
sb.append(ChatColor.DARK_AQUA).append("[PM] ");
sb.append(player.getName() + " > " + targetPlayer.getName());
sb.append(ChatColor.WHITE);
for (final String word : args) {
sb.append(word).append(' ');
}
sb.setLength(sb.length - 1);
targetPlayer.sendMessage(sb.toString());
}
I used a array loop because it just works nicely here. Instead of
for (final String word : args) {
sb.append(word).append(' ');
}
you could also write
for (int i = 0; i < args.length; i++) {
sb.append(args[i]).append(' ');
}
You might understand the second solution a little better.
Your code would slightly improve from using StringBuilders, that's true:
targetPlayer.sendMessage(ChatColor.DARK_AQUA + "[PM] "
+ player.getName() + " > " + targetPlayer.getName()
+ ChatColor.WHITE + " " + args[0])
should be changed to:
targetPlayer.sendMessage(
new StringBuilder()
.append(ChatColor.DARK_AQUA).append("[PM] ")
.append(player.getName()).append(" > ")
.append(targetPlayer.getName()).append(ChatColor.WHITE)
.append(' ').append(args[0]).build());
Note: the compiler does that for you internally, so there won't be much performance gain. However your code will be easier to debug, because the compiled code will be consistent with the source code. Otherwise, when you debug, you will keep jumping inside StringBuilder.append() calls you don't have in your source code.
but the main problem I see with your code is that you should change your many if() clauses to a switch statement:
switch(args.length){
case 0: dosomething(); break;
case 1: doSomethingElse();break;
default: doSomethingEntirelyDifferent();break;
}
Try something like this
if(args.length == 0) {
player.sendMessage(ChatColor.DARK_RED + "Usage: /pm <Target> <Message>");
} else if(args.length > 20 && player.getServer().getPlayer(args[0]) != null){
player.sendMessage(ChatColor.DARK_RED + "Error: Maximum of 20 words.");
} else {
StringBuilder argsConcat= new StringBuilder();
for(int i;i<args.length;i++) {
argsConcat.append(" "+args[i]);
}## Heading ##
targetPlayer.sendMessage(ChatColor.DARK_AQUA + "[PM] " + player.getName() + " > " + targetPlayer.getName() + ChatColor.WHITE + argsConcat.toString());
}

Java program that acts as an assembler (for a made up language): will not quit while loop

Basically, it is a two pass assembler and I am working on implementing entry points into a given assembly file. The format of the command is as follows:
Prog .ORIG
.ENT some,entry,point
some LD R0,entry
entry LD R1,point
point .FILL #42
.END some
The relevant part is the .ENT line. That is the line the assembler is getting hung up on.
The first pass takes care of handling .ENTs but it will not work for anything more than two arguments (that is, more than one comma). It does work for two operands and less, though. The code for the specific .ENT part is as follows:
String comma = ",";
String entry = "";
String[] tempEntryArray = new String[2];
int indexOfComma = read.indexOf(comma);
int startingIndex = 17;
int numOperands = 1;
while (indexOfComma != -1) {
if ((indexOfComma-startingIndex) == 0) {
return "An operand must precede the comma.";
}
if (numOperands > 4) {
return "The .ENT psuedo-op on line " + lineCounter
+ " has more than 4 operands.";
}
entry = overSubstring(read, startingIndex, indexOfComma);
if (entry.contains(" ")) {
return "The operand \"" + entry + "\" on line "
+ lineCounter + " has a space in it.";
}
if (entry.length() > 6) {
return "The operand \"" + entry + "\" on line "
+ lineCounter + " is longer than 6 characters.";
}
machineTables.externalSymbolTable.put(entry, tempEntryArray);
entry = read.substring(indexOfComma + 1);
startingIndex = indexOfComma + 1;
indexOfComma = entry.indexOf(comma);
if (indexOfComma != -1) {
indexOfComma += (startingIndex - 1);
}
numOperands++;
}
entry = overSubstring(read, startingIndex, read.length());
if (entry.contains(" ")) {
return "The operand \"" + entry + "\" on line "
+ lineCounter + " has a space in it.";
}
if (entry.length() > 6) {
return "The operand \"" + entry + "\" on line "
+ lineCounter + " is longer than 6 characters.";
}
machineTables.externalSymbolTable.put(entry, tempEntryArray);
read is a String containing one line of the input file.
overSubstring is a method that will perform similarly to substring but it will return a whitespace character if it reads a null string.
I am sorry for the huge block of code, and I know the error messages can be done a lot better, but for now I am concerned with this particular code hanging the assembler whenever there are more than two operands (more than one comma).
I would appreciate it very much if someone could help me with this problem.
Thanks.
I think that you're reading the same indexOfComma value infinitely. Instead of all that startingIndex and substring() business, just use String#indexOf(String, int) instead of String#indexOf(String) to properly skip the preceding indices you've already found.
Get indexOfComma consistently. Something like this:
int indexOfComma = -1;
int numOperands = 1;
while ((indexOfComma = read.indexOf(comma, indexOfComma+1)) != -1) {
// snip...
machineTables.externalSymbolTable.put(entry, tempEntryArray);
numOperands++;
}

Categories