Printing NUL in log file while Converting Char Arrays to String - java

I am reading response from TCP call and I have to read chars only. Reading each char takes too much time so I am creating array with maximum number the response might be. Problem in this approach that response length is less and array size is big. While converting that into String its also using those blank chars which were not used while reading response because of that its writing "NUL" into log file.
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class TestArrayToString {
public static void main(String[] args) throws IOException {
char[] chars = new char[5];
chars[0] = 'K';
chars[1] = 'S';
chars[2] = 'H';
String s = new String(chars);
System.out.println(s);
FileWriter fw = new FileWriter(new File("C://projects//test//test.log"));
fw.write(s);
fw.flush();
fw.close();
}
}
Output
Is there any possibility to remove that NUL while writing.

Arrays are objects. When they are initialized (instantiated), each element of the array is initialized to their default values. For example, primitive numeric values are initialized to the number 0. Objects are initialized by default to NULL. Character primitives or char are initialized to Unicode value 0 (\U0000) which happens to be the null character.
Your code is initializing an array of five chars. Only the first three elements are set with new character values. The last two still contain default values.
To fix this, you either need to create a smaller array, or only convert to String characters containing not null values. An easy way to do this is by trimming. Something like this should work:
char[] chars = new char[5];
...
String s = String.valueOf(chars).trim();
UPDATE
Another added benefit to this solution is avoiding creating a new String for repeated values.
String s = new String(chars); // BAD
String s = String.valueOf(chars); // Preferred
The preferred answer only creates a new String if the value represented by the array of characters is not present in the String pool. If it is, it uses the already existing String. The String copy constructor creates a duplicate String (it disregards the String pool).

Related

Splitting a string with byte length limits in java

I want to split a String to a String[] array, whose elements meet following conditions.
s.getBytes(encoding).length should not exceed maxsize(int).
If I join the splitted strings with StringBuilder or + operator, the result should be exactly the original string.
The input string may have unicode characters which can have multiple bytes when encoded in e.g. UTF-8.
The desired prototype is shown below.
public static String[] SplitStringByByteLength(String src,String encoding, int maxsize)
And the testing code:
public boolean isNice(String str, String encoding, int max)
{
//boolean success=true;
StringBuilder b=new StringBuilder();
String[] splitted= SplitStringByByteLength(str,encoding,max);
for(String s: splitted)
{
if(s.getBytes(encoding).length>max)
return false;
b.append(s);
}
if(str.compareTo(b.toString()!=0)
return false;
return true;
}
Though it seems easy when the input string has only ASCII characters, the fact that it could cobtain multibyte characters makes me confused.
Thank you in advance.
Edit: I added my code impementation. (Inefficient)
public static String[] SplitStringByByteLength(String src,String encoding, int maxsize) throws UnsupportedEncodingException
{
ArrayList<String> splitted=new ArrayList<String>();
StringBuilder builder=new StringBuilder();
//int l=0;
int i=0;
while(true)
{
String tmp=builder.toString();
char c=src.charAt(i);
if(c=='\0')
break;
builder.append(c);
if(builder.toString().getBytes(encoding).length>maxsize)
{
splitted.add(new String(tmp));
builder=new StringBuilder();
}
++i;
}
return splitted.toArray(new String[splitted.size()]);
}
Is this the only way to solve this problem?
The class CharsetEncode has provision for your requirement. Extract from the Javadoc of the Encode method:
public final CoderResult encode(CharBuffer in,
ByteBuffer out,
boolean endOfInput)
Encodes as many characters as possible from the given input buffer, writing the results to the given output buffer...
In addition to reading characters from the input buffer and writing bytes to the output buffer, this method returns a CoderResult object to describe its reason for termination:
...
CoderResult.OVERFLOW indicates that there is insufficient space in the output buffer to encode any more characters. This method should be invoked again with an output buffer that has more remaining bytes. This is typically done by draining any encoded bytes from the output buffer.
A possible code could be:
public static String[] SplitStringByByteLength(String src,String encoding, int maxsize) {
Charset cs = Charset.forName(encoding);
CharsetEncoder coder = cs.newEncoder();
ByteBuffer out = ByteBuffer.allocate(maxsize); // output buffer of required size
CharBuffer in = CharBuffer.wrap(src);
List<String> ss = new ArrayList<>(); // a list to store the chunks
int pos = 0;
while(true) {
CoderResult cr = coder.encode(in, out, true); // try to encode as much as possible
int newpos = src.length() - in.length();
String s = src.substring(pos, newpos);
ss.add(s); // add what has been encoded to the list
pos = newpos; // store new input position
out.rewind(); // and rewind output buffer
if (! cr.isOverflow()) {
break; // everything has been encoded
}
}
return ss.toArray(new String[0]);
}
This will split the original string in chunks that when encoded in bytes fit as much as possible in byte arrays of the given size (assuming of course that maxsize is not ridiculously small).
The problem lies in the existence of Unicode "supplementary characters" (see Javadoc of the Character class), that take up two "character places" (a surrogate pair) in a String, and you shouldn't split your String in the middle of such a pair.
An easy approach to splitting would be to stick to the worst-case that a single Unicode code point can take at most four bytes in UTF-8, and split the string after every 99 code points (using string.offsetByCodePoints(pos, 99) ). In most cases, you won't fill the 400 bytes, but you'll be on the safe side.
Some words about code points and characters
When Java started, Unicode had less than 65536 characters, so Java decided that 16 bits were enough for a character. Later the Unicode standard exceeded the 16-bit limit, and Java had a problem: a single Unicode element (now called a "code point") no longer fit into a single Java character.
They decided to go for an encoding into 16-bit entities, being 1:1 for most usual code points, and occupying two "characters" for the exotic code points beyond the 16-bit limit (the pair built from so-called "surrogate characters" from a spare code range below 65535). So now it can happen that e.g. string.charAt(5) and string.charAt(6) must be seen in combination, as a "surrogate pair", together encoding one Unicode code point.
That's the reason why you shouldn't split a string at an arbitrary index.
To help the application programmer, the String class then got a new set of methods, working in code point units, and e.g. string.offsetByCodePoints(pos, 99) means: from the index pos, advance by 99 code points forward, giving an index that will often be pos+99 (in case the string doesn't contain anything exotic), but might be up to pos+198, if all the following string elements happen to be surrogate pairs.
Using the code-point methods, you are safe not to land in the middle of a surrogate pair.

Storing multiple values in Java without using arrays

Take user input for 5 times, store them in a variable and display all 5 values in last. How can I do this in Java? Without using arrays, collections or database. Only single variable like String and int.
Output should look like this
https://drive.google.com/file/d/0B1OL94dWwAF4cDVyWG91SVZjRk0/view?pli=1
This seems like a needless exercise in futility, but I digress...
If you want to store them in a single string, you can do it like so:
Scanner in = new Scanner(System.in);
String storageString = "";
while(in.hasNext()){
storageString += in.next() + ";";
}
if you then input foo bar baz storageString will contain foo;bar;baz;. (in.next() will read the input strings to the spaces, and in.hasNext() returns false at the end of the line)
As more strings are input, they are appended to the storageString variable. To retrieve the strings, you can use String.split(String regex). Using this is done like so:
String[] strings = storageString.split(";");
the strings array which is retrieved here from the storageString variable above should have the value ["foo", "bar", "baz"].
I hope this helps. Using a string as storage is not optimal because JVM creates a new object every time a string is appended onto it. To get around this, use StringBuilder.
*EDIT: I originally had said the value of the strings array would be ["foo", "bar", "baz", ""]. This is wrong. The javadoc states 'Trailing empty strings are therefore not included in the resulting array'.
public static void main(String[] args) {
String s = "";
Scanner in = new Scanner(System.in);
for(int i=0;i<5;i++){
s += in.nextLine();
}
System.out.println(s);
}
Why dont you use Stingbuilder or StringBuffer, keep appending the some delimiter followed by the input text.
Use simple String object and concatenate it with new value provided by user.
String myString = "";
// while reading from input
myString += providedValue;

Array Index out of Bound Exception for returning Char Array

I am new to Java programming and I was writing code to replace spaces in Strings with %20 and return the final String. Here is the code for the problem. Since I am new to programming please tell me what I did wrong. Sorry for my bad English.
package Chapter1;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Problem4 {
public char[] replaceSpaces(char[] str_array, int length)
{
int noOfSpaces=0,i,newLength;
for(i=0;i<length;i++)
{
if(str_array[i]==' ')
{
noOfSpaces++;
}
newLength = length + noOfSpaces * 2;
str_array[newLength]='\0';
for(i=0;i<length-1;i++)
{
if(str_array[i]==' ')
{
str_array[newLength-1]='0';
str_array[newLength-2]='2';
str_array[newLength-3]='%';
newLength = newLength-3;
}
str_array[newLength-1]=str_array[i];
newLength = newLength - 1;
}
}
return str_array;
}
public static void main(String args[])throws Exception
{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Please enter the string:");
String str = reader.readLine();
char[] str_array = str.toCharArray();
int length = str.length();
Problem4 obj = new Problem4();
char[] result = obj.replaceSpaces(str_array, length);
System.out.println(result);
}
}
But I get the following error:
Please enter the string:
hello world
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 11
at Chapter1.Problem4.replaceSpaces(Problem4.java:19)
at Chapter1.Problem4.main(Problem4.java:46)
How about using String.replaceAll():
String str = reader.readLine();
str = str.replaceAll(" ", "02%");
Sample code here
EDIT:
The problem is at line 19:
str_array[newLength]='\0';//<-- newLength exceeds the char array size
Here array is static i.e. the size is fixed you can use StringBuilder, StringBuffer, etc to build the new String without worrying about the size for such small operations.
Assuming that you want to see what mistakes you made when implementing your approach, instead of looking for a totally different approach:
(1) As has been pointed out, once an array has been allocated, its size cannot be changed. Your method takes str_array as a parameter, but the resulting array will likely be larger than str_array. Therefore, since str_array's length cannot be changed, you'll need to allocate a new array to hold the result, rather than using str_array. You've computed newLength correctly; allocate a new array of that size:
char[] resultArray = new char[newLength];
(2) As Elliott pointed out, Java strings don't need \0 terminators. If, for some reason, you really want to create an array that has a \0 character at the end, then you have to add 1 to your computed newLength to account for the extra character.
(3) You're actually creating the resulting array backward. I don't know if that is intentional.
if(str_array[i]==' ')
{
str_array[newLength-1]='0';
str_array[newLength-2]='2';
str_array[newLength-3]='%';
newLength = newLength-3;
}
str_array[newLength-1]=str_array[i];
newLength = newLength - 1;
i starts with the first character of the string and goes upward; you're filling in characters starting with the last character of the string (newLength) and going backward. If that's what you intended to do, it wasn't clear from your question. Did you want the output to be "dlrow%20olleh"?
(4) If you did intend to go backward, then what the above code does with a space is to put %20 in the string (backwards), but then it also puts the space into the result. If the input character is a space, you want to make sure you don't execute the two lines that copy the input character to the result. So you'll need to add an else. (Note that this problem will lead to an out-of-bounds error, because you're trying to put more characters into the result than you computed.) You'll need to have an else in there even if you really meant to build the string forwards and need to change the logic to make it go forward.
Java arrays are not dynamic (they are Object instances, and they have a field length property that does not change). Because they store the length as a field, it is important to know that they're not '\0' terminated (your attempt to add such a terminator is causing your index out of bounds Exception). Your method doesn't appear to access any instance fields or methods, so I'd make it static. Then you could use a StringBuilder and a for-each loop. Something like
public static char[] replaceSpaces(char[] str_array) {
StringBuilder sb = new StringBuilder();
for (char ch : str_array) {
sb.append((ch != ' ') ? ch : "%20");
}
return sb.toString().toCharArray();
}
Then call it like
char[] result = replaceSpaces(str_array);
Finally, you might use String str = reader.readLine().replace(" ", "+"); or replaceAll(" ", "%20") as suggested by #Arvind here.
P.S. When you finally get your result you'll need to fix your call to print it.
System.out.println(Arrays.toString(result));
or
System.out.println(new String(result));
A char[] is not a String and Java arrays (disappointingly) don't override toString() so you'll get the one from Object.
please tell me what I did wrong
You tried to replace a single character with three characters %20. That's not possible because arrays are fixed length.
Therefore you must allocate a new char[] and copy the characters from str_array into the new array.
for (i = 0; i < length; i++) {
if (str_array[i] == ' ') {
noOfSpaces++;
}
}
newLength = length + noOfSpaces * 2;
char[] newArray = new char[newLength];
// copy characters from str_array into newArray
The exception is raised in this line str_array[newLength]='\0'; because value of newLength is greater than length of str_array.
Array size cannot be increased once it is defined. So try the alternative solution.
char[] str_array1=Arrays.copyOf(str_array, str_array.length+1);
str_array1[newLength]='\0';
don't forget to import the new package import java.util.Arrays;

Printing 1D array of chars, ints in java using System.out.println(arr)

I am printing a 1d array of chars by using System.out.println(arr) and I get the characters in the array (not space seperated). When I do the same by adding a "/t", the output changes and it now prints the address of the char array.
I tried to print a 1d array of ints using System.out.println(arr), but the results were different and it printed the location of the array in memory.
Please tell what is going on and how is it all implemented.
import java.io.*;
import java.math.*;
import java.util.*;
import java.lang.*;
class Main3{
public static void main(String[] args)throws java.lang.Exception{
int[] intArr = {1,2,3,4};
char[] charArr = {'a' , 'b' };
System. out.println(intArr); // prints the address of the intArr
System. out.println(charArr); // prints the charArr contents
System.out.println("\t" + charArr); // prints the address of the charArr after a tab
}
}
PrintStream has a method that accepts a char[].
However when you do "\t" + charArray java tries to do String concatenation. To do this it first has to convert charArray to a String using the Object#toString method(JLS 5.1.11). Then it passes the String into println.
The following print statement:
System.out.println(charArr);
invokes the PrintStream#println(char[]) method. From the documentation:
The characters are converted into bytes according to the platform's default character encoding, and these bytes are written in exactly the manner of the write(int) method.
Whereas the next print statement:
System.out.println("\t" + charArr);
converts the charArray to String, by invoking the toString() method of Object class, as arrays don't override it. And then the method PrintStream#println(String) is invoked.
So, the above print statement is equivalent to:
System.out.println("\t" + charArr.toString());
Look into the Object#toString() method to see how it forms the string for the array.
The way to access the elements of the array is with bracket notation. So for example if you want the get the int at index 0 of the intArr you could write
System.out.println(intArr[0]);
where the number in brackets is the index of the element you want or you could iterate over all of them with
for(int i = 0; i < intArr.length; i++){
System.out.println(intArr[i]);
}
This will work as long as whats in the array is not an object - in which case it will print the address.

what is 'new StringBuffer(aString)' in java?

I see a program to reverse a string
public class ReverseName{
public static void main(String[]args)
{
String name=args[0];
String reverse=new StringBuffer(name).reverse().toString();
System.out.println(reverse);
}
}
so what is new StringBuffer(name).reverse().toString(); all about?
String reverse=new StringBuffer(name).reverse().toString();
Let's break this down.
new StringBuffer(name)
First off we create a new StringBuffer (I'd have used StringBuilder as we don't need thread safety) with the contents of name. This just allows a more peformant way to append strings but here it's used for the next part.
.reverse()
This calls the reverse method on the StringBuffer which returns a reversed StringBuffer.
.toString();
Finally this is turned back into a String.
You can split that into 3 lines for understanding
StringBuffer reverseBuffer = new StringBuffer(name); // Creating new StringBuffer object
reverseBuffer = reverseBuffer.reverse(); //Reversing the content using StringBuffer
String reverse = reverseBuffer.toString(); // Converting StringBuffer to String and saving in reverse
just a StringBuffer object reversing a string
You instantiate the StringBuffer object with the "name" String object , then reverse it.
From the JAVA API
public StringBuffer reverse()
Causes this character sequence to be replaced by the reverse of the sequence. If there are any surrogate pairs included in the sequence, these are treated as single characters for the reverse operation. Thus, the order of the high-low surrogates is never reversed. Let n be the character length of this character sequence (not the length in char values) just prior to execution of the reverse method. Then the character at index k in the new character sequence is equal to the character at index n-k-1 in the old character sequence.
Note that the reverse operation may result in producing surrogate pairs that were unpaired low-surrogates and high-surrogates before the operation. For example, reversing "\uDC00\uD800" produces "\uD800\uDC00" which is a valid surrogate pair.
Returns:
a reference to this object.
Since:
JDK1.0.2
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/StringBuffer.html#reverse%28%29
Actually String is an immutable class, that means once object of String is created its contents cannot be modified. Therefore we use StringBuffer to construct strings. In above example, object of StringBuffer is created with content name, String in name is reversed in same object of StringBuffer(as it is mutable). Again converted to String object and assigned that object to reverse object reference.

Categories