How to use StringBuilder properly instead of an excessively long method - java

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());
}

Related

String return value in recursive function in java

So I'm practicing java currently, I'm a beginner and I try to explain all the examples that I code so I can understand how and why things are like that. I understand the concept of recursion but I came across this problem when I tried to explain this code:
import java.util.Scanner;
public class JavaExample {
public static void main(String[] args) {
String str;
System.out.println("Enter your username: ");
Scanner scanner = new Scanner(System.in);
str = scanner.nextLine();
scanner.close();
String reversed = reverseString(str);
System.out.println("The reversed string is: " + reversed);
}
public static String reverseString(String str)
{
if (str.isEmpty())
return str;
//Calling Function Recursively
return reverseString(str.substring(1)) + str.charAt(0);
}
}
With my knowledge so far about recursion, I tried to explain it like this.
Let's have for example a string "Petar":
reverseString(etar)+P
reverseString((tar)+etar)+P
reverseString((ar)+tar+etar)+P
reverseString((r)+ar+tar+etar)+P
-----------------------------------
r+ar+tar+etar+P
I noticed that the right answer is the first character from every individual piece, so I must be close.
Thank you for your time and I'm sorry if I didn't express myself clearly, I'm from Europe (sry bad inglish).
You doing good for first line reverseString(etar)+P you keep at the end only the *first char**, just do the same for next lines
put first char at the end
send the rest to the method
reverseString(etar)+P
reverseString(tar) +e+P
reverseString(ar) +t+e+P
reverseString(r) +a+t+e+P
reverseString('') +r+a+t+e+P // stops when empty string is passed
You got the first call right but the others were a bit off. In each recursive call you return the the string with the first character at the end instead of the begining. Thus, the recursion looks something like this:
reverseString("Petar")
return reverseString("etar") + "P"
return reverseString("tar") + "e"
return reverseString("ar") + "t"
return reverseString("r") + "a"
return reverseString("") + "r"
return ""
So the function will return: (((((("")+"r")+"a")+"t")+"e")+"P"), which is "rateP".
It should become clear when start with the simplest possible example: the empty string and string of size 1. Then substituting arguments of each call, to make it more obvious:
// string.isEmpty() is true, so the empty string is returned immediately
reverse("") -> ""
reverse("a") -> reverse("") + 'a' -> ("") + 'a' -> "a"
These are the trivial examples, let's try it with longer strings:
reverse("ab") -> reverse("b") + 'a'
reverse("abc") -> reverse("bc") + 'a'
-> (reverse("c") + 'b') + 'a'
-> ((reverse("") + 'c') + 'b') + 'a'
-> ((("") + 'c') + 'b') + 'a'
-> "cba"
The general pattern should be clear now. For the sake of completeness, let's manually "unroll" the recursive calls for a 4 character string:
reverse("abcd") -> reverse("bcd") + 'a'
-> (reverse("cd") + 'b') + 'a'
-> ((reverse("d") + 'c') + 'b') + 'a'
-> (((reverse("") + 'd') + 'c') + 'b') + 'a'
-> (((("") + 'd') + 'c') + 'b') + 'a'
-> "dcba"
It works like this:
reverseString("Peter") =
reverseString("eter") + P =
(reverseString("ter") + e) + P =
((reverseString("er") + t) + e) + P =
(((reverseString("r") + e) + t) + e) + P =
((((reverseString("") + r) + e) + t) + e) + P =
(((("" + r) + e) + t) + e) + P =
((((r) + e) + t) + e) + P =
(((r + e) + t) + e) + P =
(((re) + t) + e) + P =
((re + t) + e) + P =
((ret) + e) + P =
(ret + e) + P =
(rete) + P =
rete + P =
reteP
On your example when your function reaches only one character like
Peter when it becomes only "P"
and the string is not empty you call
substring(1)
Which calls an index out of the range while the string only have P on index 0 and none on index 1
You have to put a base case that checks if the string length is equal to 1 or less

ArrayIndexOutOfBounds Exception, but not out of bounds?

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];

How to call a variable FROM another method INSIDE the main the method to perform a math calculation

Maybe I'm just stupid (probably) but I have been struggling with this for LITERALLY the past five hours and I really can't figure it out. Nothing on this site / google seems to help me; everyone wants to know how to call a method that's defined in the main method in another method, but I am trying to do it the other way around. I am new to java, but I am aware that you can't directly call a variable from a method into another method. However, I have tried so many different iterations of trying to get the values and NOTHING is compiling and I get the same errors over and over again: "error: cannot find symbol" for all of my variables.
All I am trying to do is read a text file and print out what percentage of the words are of x length up to 13 and say how many of those words are in the document so like "Proportion of 1- letter words: .7% (2 words)" is printed out all the way to "Proportion of 13- letter words: 80.7% (7000 words)" (this is how the output is supposed to look, I know it's not pretty).
Anyway please help me because I am stuck and tearing my hair out.
import java.util.*;
import java.io.*;
public class FileReader
{
public static void main (String [] args)throws FileNotFoundException
{
WordCount();
WordLengthCount();
File file = new File("RomeoAndJuliet.txt");
Scanner keyboard = new Scanner(new FileInputStream(file));
System.out.println("Proportion of 1-letter words: " + count1/count + "% (" + count1 + " words)");
System.out.println("Proportion of 2-letter words: " + count2/count + "% (" + count2 + " words)");
System.out.println("Proportion of 3-letter words: " + count3/count + "% (" + count3 + " words)");
System.out.println("Proportion of 4-letter words: " + count4/count + "% (" + count4 + " words)");
System.out.println("Proportion of 5-letter words: " + count5/count + "% (" + count5 + " words)");
System.out.println("Proportion of 6-letter words: " + count6/count + "% (" + count6 + " words)");
System.out.println("Proportion of 7-letter words: " + count7/count + "% (" + count7 + " words)");
System.out.println("Proportion of 8-letter words: " + count8/count + "% (" + count8 + " words)");
System.out.println("Proportion of 9-letter words: " + count9/count + "% (" + count9 + " words)");
System.out.println("Proportion of 10-letter words: " + count10/count + "% (" + count10 + " words)");
System.out.println("Proportion of 11-letter words: " + count11/count + "% (" + count11 + " words)");
System.out.println("Proportion of 12-letter words: " + count12/count + "% (" + count12 + " words)");
System.out.println("Proportion of 13-letter words: " + count13/count + "% (" + count13 + " words)");
}
public static int WordCount(int n)throws FileNotFoundException
{
File file = new File("RomeoAndJuliet.txt");
Scanner keyboard = new Scanner(new FileInputStream(file));
int countABC=0;
while(keyboard.hasNext())
{
keyboard.next();
countABC++;
}
return countABC;
}
public static int WordLengthCount(int n) throws FileNotFoundException
{
File file = new File("RomeoAndJuliet.txt");
Scanner keyboard = new Scanner(new FileInputStream(file));
int count1 = 0;
int count2 = 0;
int count3 = 0;
int count4 = 0;
int count5 = 0;
int count6 = 0;
int count7 = 0;
int count8 = 0;
int count9 = 0;
int count10 = 0;
int count11 = 0;
int count12 = 0;
int count13 = 0;
int blob = 0; // so that if statement runs
while(keyboard.hasNext())
{
if (keyboard.next().length() == 1)
{
count1++;
keyboard.next();
return count1;
}
else if (keyboard.next().length() == 2)
{
count2++;
keyboard.next();
return count2;
}
else if (keyboard.next().length() == 3)
{
count3++;
keyboard.next();
return count3;
}
else if (keyboard.next().length() == 4)
{
count4++;
keyboard.next();
return count4;
}
else if (keyboard.next().length() == 5)
{
count5++;
keyboard.next();
return count5;
}
else if (keyboard.next().length() == 6)
{
count6++;
keyboard.next();
return count6;
}
else if (keyboard.next().length() == 7)
{
count7++;
keyboard.next();
return count7;
}
else if (keyboard.next().length() == 8)
{
count8++;
keyboard.next();
return count8;
}
else if (keyboard.next().length() == 9)
{
count9++;
keyboard.next();
return count9;
}
else if (keyboard.next().length() == 10)
{
count10++;
keyboard.next();
return count10;
}
else if (keyboard.next().length() == 11)
{
count11++;
keyboard.next();
return count11;
}
else if (keyboard.next().length() == 12)
{
count12++;
keyboard.next();
return count12;
}
else if (keyboard.next().length() == 13)
{
count13++;
keyboard.next();
return count13;
}
} return blob;
}
}
thanks!
Make the variable static and call it from the main method
There are a couple of things wrong in your code, but the biggest one is that you are returning the count when you find a word that has a specific Length.
You may want to create a class (say Document) that has the attributes you listed as variables in WordLengthCount (int count1, int count2, etc). Since attributes should most often be private, I would suggest doing an increment count method.
Finally, your WordLengthCount, can call the increment count method for the right word type, and return the object that you have created.
Moreover, instead of creating 13 variables, I would recommend using an array instead
int[] wordCount= new int[13];
You're trying to access local variables of one function in some other function. This is not possible. As the name suggests, local variables are local to the block or function in which they are declared. If you want to globally access these variables, make them class-level variables, i.e. declare them inside the class body but outside of any other function. Also, if you want to access them from static methods without creating object of the class, make these variables static.

CompareTo method not working as expected for my address book

public void compareTo(String lname1, String lname2) {
/* Note to self: Using this method is case sensitive, because
it only prints if names are found in the array. And those names
are case sensitive inside the array, even though I'm using the
CompareTo method from java's String
class which is NOT inherently case sensitive. ???????? */
boolean foundContact = false;
for(int i = 0; i < arrayOfPersons.size(); i++){
if(arrayOfPersons.get(i).getFname().equals(lname1) && (arrayOfPersons.get(i).getFname().equals(lname2))) {
lname1.compareTo(lname2);
foundContact = true;
}
}
if (foundContact == false)
System.out.println("This option is case sensitive. Check your spelling and try again. Otherwise these contacts do not exist.");
if(lname1.compareTo(lname2) < 0)
System.out.println(lname1 + " comes after " + lname2 + " .");
if(lname1.compareTo(lname2) == 0)
System.out.println(lname1 + " are equal " + lname2 + ".");
if(lname1.compareTo(lname2) > 0)
System.out.println(lname1 + " comes before " + lname2 + " .");
}
case 6:
System.out.println("Enter last name #1:");
String lname3 = scnr.next();
System.out.println("Enter last name #2:");
String lname4 = scnr.next();
Necronomicon.compareTo(lname3, lname4);
break;
// This case is from my main and shows how I use the compareTo method. Just one of many options to my address book.
I created an address book. One of the requirements for my address book is to compare two people by last name. This is the method I wrote to accomplish that goal. However, it's case sensitive when used, so I tried writing a warning to the user.
But the warning prints regardless of whether the contacts are found in the arrayOfPersons. So I think that my boolean is not updating correctly or the way I'm checking to see if the two names exist in the persons array is wrong? Is that right?
Have you tried doing like this ?
boolean foundlname1 = false,foundlname2 = false;
for(int i = 0; i < arrayOfPersons.size(); i++)
{
if(arrayOfPersons.get(i).getFname().equals(lname1) && !foundlname1)
foundlanme1 = true;
if(arrayOfPersons.get(i).getFname().equals(lname2) && !foundlname2)
foundlanme2 = true;
if(foundlanme1 && foundlanme2)
{
foundContact = true;
break;
}
}
if (foundContact == false)
System.out.println("This option is case sensitive. Check your spelling and try again. Otherwise these contacts do not exist.");
else if(lname1.compareToIgnoreCase(lname2) > 0)
System.out.println(lname1 + " comes after " + lname2 + " .");
else if(lname1.compareToIgnoreCase(lname2) == 0)
System.out.println(lname1 + " are equal " + lname2 + ".");
else
System.out.println(lname1 + " comes before " + lname2 + " .");
}
Your if statement in the for loop will never be true unless lname1 and lname2 are equals. I don't know if what you did is what you wanted to do. You can do like this which is similar to your code you already have:
In the compareTo method check if the arrayOfPersons contains those two Persons
if(arrayOfPersons.contains(Person1) && arrayOfPersons.contains(Person2)
and then compare lname1 and lname2 like you did with your last three if statements
Note that to use the contains method you need to ovverride in your Person class the equals method
public void compareTo(String lname1, String lname2) {
boolean foundContact1 = false;
boolean foundContact2 = false;
for(int i = 0; i < arrayOfPersons.size(); i++){
if(arrayOfPersons.get(i).getLname().equals(lname1)) {
foundContact1 = true;
}
}
for(int i = 0; i < arrayOfPersons.size(); i++){
if(arrayOfPersons.get(i).getLname().equals(lname2)) {
foundContact2 = true;
}
}
if (foundContact1 && foundContact2 == false)
System.out.println("This option is case sensitive. Check your spelling and try again. Otherwise these contacts do not exist.");
if(foundContact1 && foundContact2 == true) {
if(lname1.compareTo(lname2) < 0)
System.out.println(lname1 + " comes after " + lname2 + " .");
else if(lname1.compareTo(lname2) == 0)
System.out.println(lname1 + " are equal " + lname2 + ".");
else if(lname1.compareTo(lname2) > 0)
System.out.println(lname1 + " comes before " + lname2 + " .");
}
}
I figured it out. This is what I was looking for. Thanks for the pointers everybody. Similar to solution to what Shreshta proposed, just had to modify his logic a little bit.

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