I am not able to understand the following behavior of StringBuilder when NULL objects are appended to an instance:
public class StringBufferTest {
/**
* #param args
*/
public static void main(String[] args) {
String nullOb = null;
StringBuilder lsb = new StringBuilder();
lsb.append("Hello World");
System.out.println("Length is: " + lsb.length());// Prints 11. Correct
lsb.setLength(0);
System.out.println("Before assigning null" + lsb.length());
lsb.append(nullOb);
System.out.println("Length now is:" + lsb.length()); // Prints 4. ???
}
}
The last print statement does not print 0. Can anyone please help me understand the behavior?
From the StringBuffer API -
http://download.oracle.com/javase/1.5.0/docs/api/java/lang/StringBuffer.html#append(java.lang.String)
The characters of the String argument are appended, in order,
increasing the length of this sequence by the length of the argument.
If str is null, then the four characters "null" are appended.
This should explain the length as 4.
StringBuilder appends "null" when you give it a null reference. It eases debugging. If you want an empty string instead of "null", just test the reference before appending:
if (obj != null) {
builder.append(obj);
}
No, you set the length to 0; the "Before assigning null" prints 0.
Then you append null, which will appear in the buffer as the string "null", which has length four.
Related
In the below code, I am getting the StringIndexOutOfBoundsException in sBuilder.insert(pos,words[i]); line,
I have initialized the length here new StringBuilder(s.length()) for the below input,
System.out.println(sortSentence("is2 sentence4 This1 a3"));
public static String sortSentence(String s) {
StringBuilder sBuilder=new StringBuilder(s.length());
String words[]= s.split(" ");
for(int i=0;i<words.length;i++)
{
int pos= Integer.parseInt(words[i].replaceAll("\\D+",""));
// this is the line of error
sBuilder.insert(pos,words[i]);
}
return sBuilder.toString();
}
This is the error I am getting,
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: offset 2, length 0
The length of the input String is 22 how can I get this error despite of this ?
If you check the code where the exception is raised it becomes clearer. StringBuilder's content has no such index, and the capacity from the constructor doesn't fill it by default.
static void checkOffset(int offset, int length) {
if (offset < 0 || offset > length) {
throw new StringIndexOutOfBoundsException("offset " + offset +
", length " + length);
}
}
Also the javadoc says it:
Inserts the string representation of the Object argument into this
character sequence. The offset argument must be greater than or equal
to 0, and less than or equal to the length of this sequence.
Throws: StringIndexOutOfBoundsException – if the offset is invalid.
Note: length, not capacity, of StringBuilder, not of the input string.
For the notion that sBuilder.setLength(s.length()); solves the problem: only if the perceived problem is the exception alone. setLength initializes the internally used array with (byte)0 btw, which gives a rather odd string as a result.
But then, why use a string builder in the first place? Just set everything in the original string to " " which is not an integer, can be done with a single regex like this one: s.replaceAll("[^0-9]", " ").
Or the other way: don't insert into stringbuilder, just append, solves the problem too, maybe, depending on the interpretation.
Looks like the whole issue belongs more on a code review site, imho.
What I understand that you are simply trying to remove spaces. I may suggest to go for much simpler approach. No need to start with capacity at all.
public class MyClass {
public static String sortSentence(String s) {
StringBuilder sBuilder=new StringBuilder();
String words[]= s.split(" ");
for(int i=0;i<words.length;i++)
{
int pos= Integer.parseInt(words[i].replaceAll("\\D+",""));
// this is the line of error
sBuilder.append(words[i]);
}
return sBuilder.toString();
}
public static void main(String args[]) {
System.out.println(sortSentence("is2 sentence4 This1 a3"));
}
}
OR
Simply use String replaceAll() method.
I'm writing a parser with StreamTokenizer. I need an input like "8a" to echo an error that a number contains a char. Instead, it prints:
NUM: 8 ID: a
It seems to be identifying the char as a separate token, even though no whitespace separates them.
Is there a workaround?
You can override StringTokenizer's parseNumbers method to disable special handling of number characters.
Please be aware this might be very risky and otherwise unsuitable.
As per javadoc https://docs.oracle.com/javase/7/docs/api/java/io/StreamTokenizer.html#parseNumbers():
* When the parser encounters a word token that has the format of a
* double precision floating-point number, it treats the token as a
* number rather than a word, by setting the {#code ttype}
* field to the value {#code TT_NUMBER} and putting the numeric
* value of the token into the {#code nval} field.
Here comes example - I am not adding 'numeric' attribute to typical characters used in numbers:
final Reader rd = new StringReader("8a");
final StreamTokenizer tk = new StreamTokenizer(rd) {
#Override
public void parseNumbers() {
// super.parseNumbers(); - by not calling super. I disable special handling of numeric characters
}
};
tk.wordChars('a', 'z');
tk.wordChars('0', '9');
while ((tk.nextToken()) != StreamTokenizer.TT_EOF) {
if (tk.ttype == StreamTokenizer.TT_WORD) {
System.out.println("TT_WORD " + tk.sval);
}
if (tk.ttype == StreamTokenizer.TT_NUMBER) {
System.out.println("TT_NUMBER " + tk.nval);
}
}
outputs:
TT_WORD 8a
With the above config, you could then get a String 8a and then do String.contains to check if a number is present inside.
You could identify if the current token is a StreamTokenizer.TT_WORD and output an error. Check the code snippet below it takes a text with numbers and characters without spaces and outputs an error when it reaches a character.
import java.io.*;
public class StreamCharacterChecker{
public static void main(String []args) throws IOException{
String text = "123458a787";
Reader r = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(text.getBytes())));
StreamTokenizer st = new StreamTokenizer(r);
int token;
while ((token = st.nextToken()) != StreamTokenizer.TT_EOF){
if (token == StreamTokenizer.TT_WORD){
System.out.println("Error characters detected!");
break;
}
}
}
}
This is a problem I've encountered several times, and always wondered why.
For my code below as an example, if a string of whitespace is entered, the method will not print. However, after the next input with a value string containing characters, it will print all the whitespace strings and the valid character containing string. Why is this delayed and stored in memory?
Example for the code below:
Enter " " returns nothing.
Enter " " returns nothing.
Enter "SwiggitySwooty" returns " " \n " " \n "SwiggitySwooty"
Explaination: The whitespace containing strings are delayed until a valid character string is entered.
Extra info: I use intellij, also happens when not sending the string to a method. I've also had this happen during a while(input.hasNext()) statement, in which I try to catch an invalid input as a string, when I want to take an integer. If I enter 'n' amount of legitimate integers, and then a string, it would print out my "please enter an integer" that 'n' amount of times like in this code.
Lastly, if anyone thinks of a better title for this, let me know so I can change it for more exposure for those with similar questions. Thank you.
Let me know if you guys need anything else!
/**
* Created by JacobHein on 4/19/15.
*/
import java.util.Scanner;
public class FizzString {
/*TODO
* Given a string str, if the string starts with "f" return "Fizz".
If the string ends
* with "b" return "Buzz". If both the "f" and "b" conditions are true, return
* "FizzBuzz". In all other cases, return the string unchanged. */
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
while(input.hasNext()) {
System.out.println(fizzString(input.nextLine()));
}
}
public static String fizzString(String str) {
String result=str;
int l=str.length();
if (str.charAt(0)=='f'||str.charAt(l-1)=='b') {
result="";
if (l>0) {
if (str.charAt(0)=='f') {
result="Fizz";
}
if (str.charAt(0)=='b') {
result="Buzz";
}
if (l>1) {
/*technique: continue the process if l>1 (within l>0 if statement),
prevents breaking the program.*/
if (str.charAt(l-1)=='b') {
result="Buzz";
}
if (str.charAt(0)=='f'&&str.charAt(l-1)=='b') {
result="FizzBuzz";
}
}/*end l>1*/
}/*end l>0*/
}/*end charAt if*/
return result;
}
}
I believe this is what you're looking for:
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String inputLine = "";
do {
inputLine = input.nextLine();
System.out.println(fizzString(inputLine));
System.out.println("");
} while (inputLine.length() > 0);
System.out.println("Goodbye");
}
public static String fizzString(String str) {
// Given a string
// If both the "f" and "b" conditions are true, return FizzBuzz
if (str.startsWith("f") && str.endsWith("b")) {
return "FizzBuzz";
}
// If the string starts with "f" return "Fizz".
if (str.startsWith("f")) {
return "Fizz";
}
// If the string ends with "b" return "Buzz".
if (str.endsWith("b")) {
return "Buzz";
}
// In all other cases, return the string unchanged.
return str;
}
Results:
The problem is the behavior of the Scanner class:
The next and hasNext methods and their primitive-type companion methods
(such as nextInt and hasNextInt) first skip any input that matches the
delimiter pattern, and then attempt to return the next token. Both
hasNext and next methods may block waiting for further input. Whether a
hasNext method blocks has no connection to whether or not its
associated next method will block.
Internally, the Scanner class is performing the following operation:
while (!sourceClosed) {
if (hasTokenInBuffer())
return revertState(true);
readInput();
}
The method hasTokenInBuffer() skips all the delimiter tokens (by default is \p{javaWhitespace}+), so only when the class found a non-delimiter token, it returns true in the hasNext() method.
For example, if you type this content: "\n\n\n5\n" and then execute nextInt() method, you'll obtain a result of 5, because Scanner automatically skips all the return line characters.
If you want to find some string into a line, try with the method java.util.Scanner.findInLine instead of nextLine().
Use the patterns: ^f(.)* to look for every line that starts with a f character and the pattern (.)*b$ to look for every line that ends with a b character.
I created a method to output a String. Using the split method and a for loop, I added each word in my sentence into a String array, replacxing the last two letters of each word with "ed". Now, my return statement should return each of the words. When I used System.out.print, it worked. When I use a return and call it in my main method, I get this output: "[Ljava.lang.String;#1b6235b"
The error seems so simple but I just don't know where I'm going worng. Any help would be appreciated.
Here is my method:
public String[] processInfo() {
String sentence = this.phrase;
String[] words = sentence.split(" ");
if (!this.phrase.equalsIgnoreCase("Fred")) {
for (int i = 0; i < words.length; i++) {
words[i] = words[i].substring(0, words[i].length() - 2).concat(
"ed ");
// System.out.print(words[i]);
}
}
return words;
}
You are printing arrays but arrays don't have a proper implementation of toString() method by default.
What you see is
"[Ljava.lang.String;#1b6235b"
This is [Ljava.lang.String; is the name for String[].class, the java.lang.Class representing the class of array of String followed by its hashCode.
In order to print the array you should use Arrays.toString(..)
System.out.println(Arrays.toString(myArray));
A good idea however, it returns my Strings in an Array format. My aim
is to return them back into sentence format. So for example, if my
input is, "Hey my name is Fred", it would output as, "Hed ed naed ed
Fred". Sorry, I forgot to add that it also seperates it with commas
when using Arrays.toString
Then you should modify your processInfo() returning a String or creating a new method that convert your String[] to a String.
Example :
//you use like this
String [] processInfoArray = processInfo();
System.out.println(myToString(processInfoArray));
// and in another part you code something like this
public static String myToString(String[] array){
if(array == null || array.length == 0)
return "";
StringBuilder sb = new StringBuilder();
for(int i=0;i<array.length-1;i++){
sb.append(array[i]).append(" ");
}
return sb.append(array[array.length -1]).toString();
}
As much as I can get from your question and comment is that your aim is to return them back into sentence format. So for example, if your input is, "Hey my name is Fred", it would output as, "Hed ed naed ed Fred".
In that case you should return a String, and not an array. I have modified your method a bit to do so. Let me know if you wanted something else.
public String processInfo() {
String sentence = this.phrase;
String[] words = sentence.split(" ");
if (!this.phrase.equalsIgnoreCase("Fred")) {
sentence = "";
for (int i = 0; i < words.length; i++) {
words[i] = words[i].substring(0, words[i].length() - 2).concat(
"ed ");
sentence += " " + words[i];
// System.out.print(words[i]);
}
}
return sentence.trim();
}
Your commented out call to System.out.print is printing each element of the array from inside the loop. Your method is returning a String[]. When you try to print an array, you will get the java representation of the array as you are seeing. You either need to change your method to build and return a string with all the array entries concatenated together, or your calling code needs to loop through the returned array and print each entry.
Hy!
I want to parse a String to a Integer.
The String is like the format for series: SXXEXXX
The Code should increase the episode.
Like: S01E01 --> S01E02
Also: S01E100 --> S01E101
Code:
String s = episodes.get(episodes.size()-1);
Log.e("DBManager",s);
if (s.split("E").length <= 2) {
int i = Integer.getInteger(s.split("E")[1].split(" ")[0]); //NullPointerEx
return s.split("E")[0]+"E"+String.valueOf(i++);
}
Log:
10-26 15:56:34.635: E/DBManager(932): S00E01
Integer.getInteger() is not the correct method to use.
You should be using Integer.valueOf()
Integer.getInteger(String s) will return the integer system property with the key s.
The null pointer occurs because this method can't find the property with the key you supply and returns null. Java then tries to unbox this to an int and null pointers.
The null pointer exception is occuring precisely because you leave the leading 0 in the string. If you really need to leave it in there though, the following code works for me:
int i = Integer.parseInt(s.split("E")[1].split(" ")[0]);
If I understand correctly, you want to split the episode name into the parts, then get the episode number and increment it by one to get the next episode number. Don't call this split method so many times, call it once.
String episodeName = episodes.get(episodes.size()-1);
Log.e("DBManager", episodeName);
string[] splittedName = episodeName.split("E");
string returnName = "";
if (splittedName.length == 2) {
if (splittedName[1].split(" ").length > 1) {
// do something if there's a episode name too
} else {
// gets the episode number
int i = Integer.valueOf(splittedName[1]);
// returns next episode full name
if (i < 9) {
returnName = splittedName[0] + "E0" + String.valueOf(i + 1);
} else {
returnName = splittedName[0] + "E" + String.valueOf(i + 1);
}
}
}
return returnName;