Multiple string method chained in single code - java

I am working on this bit of code
public class SimpleStringTest {
public static void main(String args[])
{
String ints="123456789";
System.out.println(ints.concat("0").substring(ints.indexOf("2"),ints.indexOf("0")));
}
As per as my knowledge on java "When the multiple methods are chained on a single code statement, the methods execute from left to right" Then, Why is this bit of code throwing StringIndexOutOfBondsException?
Thanks in advance,
GPAR

Because Strings are immutable.
By invoking concat, you are not modifying ints, you are creating a new String.
Therefore by the time you invoke ints.indexOf("0"), ints is still equal to its former value and the indexOf invocation returns -1, which in turn will be the outer bound of your substring.
Try a counter-example with a mutable CharSequence such as StringBuilder:
StringBuilder ints = new StringBuilder("123456789");
System.out.println(ints.append("0").substring(ints.indexOf("2"),ints.indexOf("0")));
Output
23456789

Because ints.indexOf("0") is applied on the original String ints (not the one you concatenate).
Since there is no "0" indexOf("0") returns -1 and which throws the exception.
Your code is equivalent to this:
String ints="123456789";
int indexOne = ints.indexOf("2");
int indexTwo = ints.indexOf("0");
System.out.println(ints.concat("0").substring(indexOne, indexTwo));

Related

Why only println method is overloaded for character array but not for other arrays such as String,Integer etc?

Why println method has a different overloaded method only for character array but not for other arrays such as String,Integer etc?
For example
int intArray[] = {0,1,2};
char charArray[] = {'a','b','c'};
System.out.println(intArray);
System.out.println(charArray);
Output:
[I#19e0bfd
abc
Most likely because it was designed all around writing to character streams.
System.out is a PrintStream which delegate writes to a BufferedWriter which in turn is instance of Writer.
some Writer possibilities
void write(char[] cbuf)
abstract void write(char[] cbuf, int off, int len)
void write(int c)
void write(String str)
void write(String str, int off, int len)
Because of that mostly every void print(..) method in PrintStream uses String.valueOf() to be able to pass it over to writer and say writer.write(s)
This was noticed and proposed to implement toString in arrays
https://bugs.openjdk.java.net/browse/JDK-4168079, but obviously it was too late, due to compatibility/stability concerns. So the decision was to Implement helper methods to accomplish the same thing.
So now you may find a lot of
System.out.println(Arrays.toString(new int[]{1,2,3}))
System.out is a PrintStream (link) so it has several methods like :
public void println(Object obj) (link) used for int[] which is an object. It's used everytime your call it wih an object, and if toString() is not overloaded it'll print its "adress"
public void println(char\[\] s) (link) used for char[]
Because you cannot overload a method for each type of object in Java, the choice has been to do only this one
Seems like designers decided it because in their opinion it would be the most used way of printing array containing chars. Note that if you want to print contents of an array instead of printing its address in memory, you can use method toString() provided in Arrays class. It lets you print contents of an array in a convenient way when array contains other types of objects than char. You call it this way:
Arrays.toString(yourArray);
Another way to print contents of array is creating a loop iterating over elements of array:
for (YourClass object : yourArray) {
System.out.println(object);
}

String in Java : charAt Function use

Reversing a string can be done by concatenating the Original String through a reverse loop (from str.length-1->0)
but why is this not Working Correctly :
by adding the character by character from last positon to the 0th position:
int i = 0;
while(i<originalStr.length())
{
strRev.charAt(i)=originalStr.charAt(str.length()-1-i);
i++;
}
Strings are immutable in Java. You cannot edit them.
If you want to reverse a String for training purpose, you can create a char[], manipulate it then instantiate a String from the char[].
If you want to reverse a String for professional purpose, you can do it like this :
String reverse = new StringBuilder(originalStr).reverse().toString();
strRev.charAt(i) // use to Retrieve what value at Index. Not to Set the Character to the Index.
All we know that String is a immutable class in Java. Each time if you try to modify any String Object it will Create a new one.
eg :- String abc = "Vikrant"; //Create a String Object with "Vikrant"
abc += "Kashyap"; //Create again a new String Object with "VikrantKashyap"
// and refer to abc again to the new Object.
//"Vikrant" Will Removed by gc after executing this statement.
Better to Use StringBuffer or StringBuilder to perform reverse Operation. The only Difference between these two class is
A) StringBuffer is a Thread Safe (Synchronized). A little slow because each time need to check Thread Lock.
B) StringBuider is not Thread Safe. So, It gives you much faster Result Because it is Not Synchronized.
There are Several Third Party Jars which provides you a Features like Reverse and Many more String base Manipulation Methods
import org.apache.commons.lang.StringUtils; //Import Statement
String reversed = StringUtils.reverse(words);
In your test method, best practice is to use triple A pattern:
Arrange all necessary preconditions and inputs.
Act on the object or method under test.
Assert that the expected results have occurred.
#Test
public void test() {
String input = "abc";
String result = Util.reverse(input);
assertEquals("cba", result);
}

Arraylist toString() method and duplicate values

Below I have posted a snippet of code I have written whilst trying to replicate the game minesweeper in very simplistic terms. I've got a slight query...
The code below generates a pair of co-ordinates, checks to see if the particular co-ordinates are already held in the ArrayList, and if not, adds them to the list, repeating this process until I have a list of ten mine locations. on running the program I have found that the list contains duplicates when it shouldn't...
public class MineSweeper {
private static ArrayList mines;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
MineSweeper ms = new MineSweeper();
}
public MineSweeper(){
mines = new ArrayList(10);
generateMines();
showMines();
}
private void generateMines(){
int x = 0, y = 0, mineCount = 0;
Random rnd = new Random();
StringBuilder str = new StringBuilder();
while(mineCount != 10)
{
x = rnd.nextInt(9) + 1;
y = rnd.nextInt(9) + 1;
str.append(x).append(",").append(y);
if(!(mines.contains(str.toString())))
{
mines.add(str);
mineCount ++;
}
str = new StringBuilder();
}
}
private void showMines(){
System.out.println(mines.toString());
}
}
I believed that my if statement would catch any duplicates but was wrong.
I eventually solved the problem by changing the if statement to if(!(mines.toString().contains(str)))
Can somebody enlighten me on the difference please?
You are checking if mines contains str.toString(), but adding str, which is a StringBuilder instance. Since all the objects you're adding are StringBuilders, mines can't contain a String.
You should choose which class you're going with, and stick to it. E.g., with Strings:
if (!(mines.contains(str.toString()))) {
mines.add(str.toString());
mineCount++;
}
It could be an issue with the "if(!(mines.contains(str.toString())))", i just dont know how the coordinates are saved and accessed by the "ArrayList" object.
ArrayList contains StringBuilder's and in mines.contains(str.toString()) you compare to a String (str.toString) so you compare a StringBuilder with a String thus they are never equal.
You have quite a number of other problems as well, for example mines field is static, Random is not, etc
if we look at your if statement:
mines.contains(str.toString())
mines is an ArrayList of generic type StringBuilder (because it had undefined generic type it automatically uses ArrayList<Object> ). This can be checked if you do this
System.out.println(mines.get(1) instanceof StringBuilder); //print true
str is a StringBuilder object which you have cast to a String. You are thus comparing a StringBuilder object to a String object. It is important to note that contains() uses equals() for comparison.
this can be illustrated with this example:
StringBuilder testStrB = new StringBuilder("test");
System.out.println(testStrB.equals(testStrB.toString())); //print false
in fact, I get the warning that equals() is used on incompatible types.
with your working statement
mines.toString().contains(str)
it seems that contains() accepts a CharSequence, which is a super-interface of StringBuilder. As mines.toString uses contains() of the entire String searching for a CharSequence represented by StringBuilder, it works.
in summary:
your initial (non-working) if statement tried to use (for each element of mines)
StringBuilder.equals(String)
whereas your working if statement used
String.contains(StringBuilder)
which allows StringBuilder to be used as a CharSequence and thus compared.
for interest:
System.out.println(testStrB.toString().equals(testStrB)); //prints false
// (and incompatible types warning)
so a String cannot EQUAL a StringBuilder, but can CONTAIN it. Probably because equals() takes an Object and contains() takes a CharSequence

Convert .toBinaryString into its complement

I do not know why I am getting an error at the yy.charAt(i) assignments. It says... Variable Expected... Not value.
static int subtract(int x,int y)
{
String yy=Integer.toBinaryString(y);
System.out.println(yy);
for(int i=0;i<yy.length();i++)
{
if(yy.charAt(i)==1)
{
yy.charAt(i)=0;
}
else
{
yy.charAt(i)
}
}
int t=Integer.parseInt(yy);
return(t);
}
You can't assign values to a string's index position, strings are immutable in Java. This will never work:
yy.charAt(i)=0;
If you need to modify a string, transform it to a char[] (using the toCharArray() method), modify the array and then build a new string from that array, using the String(char[]) constructor.
Alternatively, you could use a StringBuilder to modify the characters before returning a new string.
Use a StringBuilder instead.
The code would be almost identical to what you have now, except for these changes:
StringBuilder yy = new StringBuilder(Integer.toBinaryString(y));
...
yy.setChatAt(i, '0');
I think there are a few things that are not clear to you.
I think you mean the character '0' not the value 0.
The lines else { yy.charAt(i); } have absolutely no effect. You can simply omit them.
Strings are immutable in Java (i.e. they cannot be modified in place).
Even if they were, you're syntax is wrong. Something of the form class_name.method_name() is a call to a method of a class. It returns a value that you can store, it is not the same as a variable and trying to assign to a method call makes no sense at all.
To modify Strings in Java, the best way is probably to use a StringBuilder. You create a new StringBuilder using your String, make the necessary changes on that and then convert it back into a String.
So this would look something like this:
StringBuilder builder = new StringBuilder(yy); // StringBuilder from yy.
// rest of your code here
builder.setCharAt(i, '0');
// more code
yy = StringBuilder.toString(); // convert it back to a String.
Notice that even in a StringBuilder you have to call the appropriate method and pass in the value that you want to assign to it.

Removing Backing Array From Strings

I want to get the first 4 characters of a string to compare with another string. However, when I do something like
String shortString;
shortString = longString.subString(0,3);
It takes along longString's backing array and makes it impossible to compare easily.
I've also tried converting longString into a character array and inserting each character but I always seem to end up with long string. The Android Development documents say to use the String constructor to remove the backing array but it doesn't seem to work for me either.
String shortString = new String(longString.subString(0,3));
Any suggestions would be appreciated!
First, it's string.substring() not .subString().
Second, what do you mean "impossible to compare easily"? You can compare strings with .equals() easily.
public static void main(String[] args) {
String longString = "abcdefghijklmn";
String shortString = longString.substring(0, 3);
System.out.println(shortString.equals(longString));
}
this code prints false, as it should.
Update:
If you call .substring() so that it produces string of the same length as original string (e.g. "abc".substring(0,2)) than it will return reference to the same string. So, .equals() in this case will return true.
How would you want to compare? There's built in method for simple comparison:
longString.subString(0, 3).compareTo(anotherString);
Alternatively, since String is a CharSequence, something like:
for (int i=0; i<4; i++){
if (anotherString.charAt(i) != shortString.charAt(i)) return false;
}
would work as well.
Finally, every String is constructed in backing Array, there's no way to deny it, and longString.subString(0,3) would always (except index out of bound) return a String with a 4-element Char Array.
In the event that you actually need to get rid of the backing array the following will work:
String newString = StringBuilder(oldString).toString();
This might be necessary, for example, if you are parsing strings and creating substrings and you might need to do this:
String newString = StringBuilder(oldString.substring(start,end).toString();
This creates a truly new string with a zero offset and independent backing array. Otherwise, you maintain the same backing array which, in rare cases might cause a problem for the heap because it can never be garbage collected.

Categories