I wrote this little function just for practice, but an exception ("String index out of range: 29") is thrown and I don't know why...
(I know this isn't the best way to write this function and can I use regular expressions.)
This is the code:
public String retString(String x)
{
int j=0;
int i=0;
StringBuffer y = new StringBuffer(x);
try
{
while ( y.charAt(i) != '\0' )
{
if (y.charAt(i) != ' ')
{
y.setCharAt(j, y.charAt(i));
i++;
j++;
}
else
{
y.setCharAt(j, y.charAt(i));
i++;
j++;
while (y.charAt(i) == ' ')
i++;
}
}
y.setCharAt(j,'\0');
}
finally
{
System.out.println("lalalalololo " );
}
return y.toString();
}
Are you translating this code from another language? You are looping through the string until you reach a null character ("\0"), but Java doesn't conventionally use these in strings. In C, this would work, but in your case you should try
i < y.length()
instead of
y.charAt(i) != '\0'
Additionally, the
y.setCharAt(j,'\0')
at the end of your code will not resize the string, if that is what you are expecting. You should instead try
y.setLength(j)
This exception is an IndexOutOfBoundsException but more particularly, a StringIndexOutOfBoundsException (which is derived from IndexOutOfBoundsException). The reason for receiving an error such as this is because you are exceeding the bounds of an indexable collection. This is something C/C++ does not do (you check bounds of collections manually) whereas Java has these built into their collections to avoid issues such as this. In this case, you're using the String object like an array (probably what it is in implementation) and going over the boundary of the String.
Java does not expose the null terminator in the public interface of String. In other words, you cannot determine the end of the String by searching for the null terminator. Rather, the ideal way to do this is by ensuring you do not exceed the length of the string.
Java strings are not null-terminated. Use String.length() to determine where to stop.
Looks like you are a C/C++ programmer coming to java ;)
Once you have gone out of range with .charAt (), it doesn't reach null, it reaches a StringIndexOutOfBoundsException. So in this case, you will need a for loop that goes from 0 to y.length()-1.
a much better implementation (with regex) is simply return y.replaceAll("\\s+"," "); (this even replaces other whitespace)
and StringBuffer.length() is constant time (no slow null termination semantics in java)
and similarly x.charAt(x.length()); will also throw a StringIndexOutOfBoundsException (and not return \0 like you'd expect in C)
for the fixed code:
while ( y.length()>i)//use length from the buffer
{
if (y.charAt(i) != ' ')
{
y.setCharAt(j, y.charAt(i));
i++;
j++;
}
else
{
y.setCharAt(j, y.charAt(i));
i++;
j++;
while (y.charAt(i) == ' ')
i++;
}
}
y.setLength(j);//using setLength to actually set the length
btw a StringBuilder is a faster implementation (no unnecessary synchronization)
Related
I have to write a method that has a parameter of type Integer and has to return an object of type Character.
If the value of the given parameter is presentable as a Character object,
Return it as a Character. Else return null.
My task is poorly formulated it says: "Unsafe conversions (e.g. from int to char) are not allowed in your code" I suppose it is not unsafe but also not allowed somehow?
My Code so far:
public Character methodName (Integer i) {
if (i >= 0 && i <= Character.MAX_VALUE) {
return Character.valueOf((char) i.intValue()); //unsafe conversion
}
else
return null;
}
I tried fixing it by any means but just could not come up with an solution not using the unsafe conversion, thank you very much in advance for helping!
Solution to this weird formulated task:
public Character methodName (Integer i) {
if (i >= 0 && i <= Character.MAX_VALUE) {
return (Character.toChars(i)[0]); //<- solution
}
else
return null;
}
To my mind
if (i >= 0 && i <= Character.MAX_VALUE) {
return Character.valueOf((char) i.intValue());
}
is completely safe according to your teacher's definition of "safe".
SO my teacher said it is indeed unsafe, because the value range of int is 2^32 and of char is 2^16.
The if test ensures that you only cast i.intValue() to a char when i is in the required (safe) range.
The flipside is that if a provably correct range check is not sufficient to make this "safe" enough for your teacher, then AFAIK there isn't a "safe" solution. All other less direct solutions also entail an explicit or implicit range check in some form ... and will therefore also be "unsafe".
Your conversion is safe here.
You're checking if the int is in the Character range
Then you cast using a builtin method
There might be another way but it's trickier and weird:
String iStr = Integer.toString(i.intValue())
char c = iStr.charAt(0)
Character crt = Character.valueOf(c)
I repeat myself but your approach is more than fine... I don't understand what does your teacher expect from you.
I am getting the "Must be an array type but it resolved to string" error in my code. It also says that i (in the code below) cannot be resolved to a variable which I don't get.
public class DNAcgcount{
public double ratio(String dna){
int count=0;
for (int i=0;i<dna.length();i++);
if (dna[i]== "c"){
count+= 1;
if (dna[i]=="g"){
count+=1;
double answer = count/dna.length();
return answer;
}
}
}
}
Could you guys please help me figure out where the problem lies? I'm new to coding in Java so I am not entirely comfortable with the format yet.
Thanks a lot,
Junaid
You cannot access a String's character using subscript (dna[i]). Use charAt instead:
dna.charAt(i) == 'c'
Also, "c" is a String, 'c' is a char.
One more thing - integer division ( e.g. int_a / int_b ) results in an int, and so you lose accuracy, instead - cast one of the ints to double:
double answer = count/(double)dna.length();
Use {} to define the scope of the loop. Also, as others already pointed out, use charAt instead of [] and use ' for characters, and use floating point division for the ratio.
for (int i = 0; i < dna.length(); i++) {
if (dna.charAt(i) == 'c') {
count += 1;
}
if (dna.charAt(i) == 'g') {
count += 1;
}
}
Or a bit shorter, use || to or the two clauses together
if (dna.charAt(i) == 'c' || dna.charAt(i) == 'g') {
count += 1;
}
I think you are currently a bit weak at brackets , this is what i understood from your code and corrected it;
public class DNAcgcount{
public double ratio(String dna){
int count=0;
for (int i=0;i<dna.length();i++){
if (dna.charAt(i)== 'c')
count+= 1;
if (dna.charAt(i)=='g')
count+=1;
}
double answer = count/(double)dna.length();
return answer;
}
}
After if we have to close the brackets when what you want in if is finished . I think you wanted count to be the number of time c or g is present in the dna.
You also did some other mistakes like you have to use 'c' and 'g' instead of "c" and "g" if you are using .charAt(i) because it will be treated like a character and then only you can compare .
You may view this link
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/if.html
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html
and you may also have a look at works you can do with string like charAt.
It seems like that you have a few problems with the main syntax of basic java functions like loops or if-else statement. Click here for a good tutorial on these.
You must correct your for-loop and your if-statement:
for(int i=0;i<dna.length();i++){
if(...){
...;
}
if(...){
...;
}
}
Now you wont get the Cant be resolved to a variable... exception.
Second thing is the usage of your string. You have to use it like this:
for(int i=0;i<dna.length();i++){
if(dna.charAt(i) == 'c'){
count += 1;
}
if(dna.charAt(i) == 'g'){
count += 1;
}
}
Now all your exceptions should be eleminated.
Your problem is with syntax dna[i], dna is a string and you access it as it would be an array by []. Use dna.charAt(i); instead.
You using String incorrectly. Instead of accessing via [] use dna.charAt(i).
Altough logically a string is an array of characters in Java a String type is a class (which means it has attributes and methods) and not a typical array.
And if you want to compare a single character to another enclose it with '' instead of "":
if (dna.charAt(i) == 'c')
.
.
There are two errors:
count should be double or should be casted do double answer = (double)count / dna.length();
and as mentioned above you should replace dna[i] with dna.charAt(i)
Let's say there has a string like " world ". This String only has the blank at front and end. Is the trim() faster than replace()?
I used the replace once and my mentor said don't use it since the trim() probably faster.
If not, what's the advantage of trim() than replace()?
If we look at the source code for the methods:
replace():
public String replace(CharSequence target, CharSequence replacement) {
String tgtStr = target.toString();
String replStr = replacement.toString();
int j = indexOf(tgtStr);
if (j < 0) {
return this;
}
int tgtLen = tgtStr.length();
int tgtLen1 = Math.max(tgtLen, 1);
int thisLen = length();
int newLenHint = thisLen - tgtLen + replStr.length();
if (newLenHint < 0) {
throw new OutOfMemoryError();
}
StringBuilder sb = new StringBuilder(newLenHint);
int i = 0;
do {
sb.append(this, i, j).append(replStr);
i = j + tgtLen;
} while (j < thisLen && (j = indexOf(tgtStr, j + tgtLen1)) > 0);
return sb.append(this, i, thisLen).toString()
}
Vs trim():
public String trim() {
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */
while ((st < len) && (val[st] <= ' ')) {
st++;
}
while ((st < len) && (val[len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}
As you can see replace() calls multiple other methods and iterates throughout the entire String, while trim() simply iterates over the beginning and ending of the String until the character isn't a white space. So in the single respect of trying to only remove white space before and after a word, trim() is more efficient.
We can run some benchmarks on this:
public static void main(String[] args) {
long testStartTime = System.nanoTime();;
trimTest();
long trimTestTime = System.nanoTime() - testStartTime;
testStartTime = System.nanoTime();
replaceTest();
long replaceTime = System.nanoTime() - testStartTime;
System.out.println("Time for trim(): " + trimTestTime);
System.out.println("Time for replace(): " + replaceTime);
}
public static void trimTest() {
for(int i = 0; i < 1000000; i ++) {
new String(" string ").trim();
}
}
public static void replaceTest() {
for(int i = 0; i < 1000000; i ++) {
new String(" string ").replace(" ", "");
}
}
Output:
Time for trim(): 53303903
Time for replace(): 485536597
//432,232,694 difference
Assuming that the people writing the Java library code are doing a good job1, you can assume that a special purpose method (like trim()) will be as fast, and probably faster than a general purpose method (like replace(...)) doing the same thing.
Two reasons:
If the special purpose method is slower, its implementation can be rewritten as equivalent calls to the general purpose one, making the performance equivalent in most cases. A competent programmer will do this because it reduces maintenance costs.
In the special purpose method, it is likely that there will be optimizations that can be made that don't apply in the general-purpose case.
In this case we know that trim() only needs to look at the start and end of the string ... whereas replace(...) needs to look at all of the characters in the string. (We can infer this from the description of what the respective methods do.)
If we assume "competence" then we can infer that the developers will have done the analysis and not implemented trim() sub-optimally2; i.e. they won't code trim() to examine all characters.
There is another reason to use the special purpose method over the general purpose. It makes your code simpler, easier to read, and easier to inspect for correctness. This may well be more important than performance.
This clearly applies in the case of trim() versus replace(...).
1 - We can in this case. There are lots of eyes looking at this code, and lots of people who will complain loudly about egregious performance issues.
2 - Unfortunately, it is not always as straightforward as this. A library method needs to be optimized for "typical" behavior, but it also needs to avoid pathological performance in edge-cases. It is not always possible to achieve both things.
trim() is definitely faster to type, yes. It doesn't take any parameters.
It is also much faster to understand what you where trying to do. You were trying to trim the string, rather than replacing all the spaces it contains with the empty string, knowing from other context that there is only space at the beginning and the end of the string.
Indeed much faster no matter how you look at it. Don't complicate the life of the persons who're trying to read your code. Most of the time, it will be you months later, or at least someone you don't hate.
Trim will prune the outter characters until they are non white space. I believe they trim space, tab, and new lines.
Replace will scan the entire string (so, it could be a sentense) and would replace inner " " with "", essentially compressing them together.
They have different use cases though, obviously 1 is to clean up user input where the other is to update a string where matches are found with something else.
That being said, run times: Replace will run in N time, as it will look for all matching characters. Trim will run in O(N), but most likely a just a few characters off of each end.
The idea behind trim i think came around from people would would type and input things but accidentally press space before submitting their forms, essentially trying to save the field "Foo " instead of "Foo"
s.trim() shortens a String s. This means no characters has to be moved from an index to another. It starts at the first character (s.toCharArray()[0]) of the String and shortens the String character by character until the first non-whitespace character occurs. It works the same way to shorten the String at the end. So it compresses the String. If a String has no leading and trailing whitespace trim will be ready after checking the first and the last character.
In case of " world ".trim() two steps are needed: one to remove the first leading whitespace as it is on the first index and the the second to remove the last whitespace as it is on the last index.
" world ".replace(" ", "") will need at least n = " world ".length() steps. It has to check every character if it has to be replaced. But if we take into account that the implementation of String.replace(...) needs to compile a Pattern, build a Matcher and then to replace all the matched regions it's seems far complex comparing to shorten a String.
We also have to consider that " world ".replace(" ", "") does not replace whitespaces but only the String " ". Since String replace(CharSequence target, CharSequence replacement) compiles the target using Pattern.LITERAL we cannot use the character class \s. To be more accurate we would have to compare " world ".trim() to " world ".replaceAll("\\s", ""). It is still not the same because a whitespace in String trim() is defined as c <= ' ' for each c in s.toCharArray().
Summarizing: String.trim() should be faster - especially for long strings
The description how the methods work is based on the implementation of String in Java 8. But implementations can change.
But the question should be: What do you intent to do with the string? Do you want to trim it or to replace some characters? According to it use the corresponding method.
I have some problems with the code every time I try to compile the exception java.lang.StringIndexOutOfBoundsException appears. Here is the code with the problem I really don't know what I have done wrong. In the code I try to split a string using some conditions, the string represent a polynomial.
int[] coef1= new int[20];
for(i=0;i<polinom.length()+1;i++){
if(polinom.charAt(i)=='+' )
c=polinom.charAt(i+1);
else{
if(polinom.charAt(i)=='^'){
v=Integer.parseInt(Character.toString(polinom.charAt(i+1)));
coef1[v]=Integer.parseInt(Character.toString(c));
System.out.print(coef1[v]);
}
}
}
for(i=0;i<polinom.length()+1;i++){
if(polinom.charAt(i)=='-' )
c=polinom.charAt(i+1);
else{
if(polinom.charAt(i)=='^'){
v=Integer.parseInt(Character.toString(polinom.charAt(i+1)));
coef1[v]=-Integer.parseInt(Character.toString(c));
System.out.print(coef1[v]);
}
}
}
The exception is here if(polinom.charAt(i)=='+' )
Just replace all your
for(i=0;i<polinom.length()+1;i++){
with
for(i=0;i<polinom.length()-1;i++){
As indices are 0-based and you use polinom.charAt(i+1), i+1 should never be equal (nor greater) than polinom.length.
Or if you want ot be able to test until the last character of you string (for other processing), you can ensure that polinom.charAt(i+1) gets never triggered if i == polinom.length() - 1, just add a test before processing your stuff:
for(i=0;i<polinom.length();i++){ // not using -1, looping to the end of the string
if(polinom.charAt(i)=='+' && i < polinom.length() - 1) // checking that no exception will be thrown
c=polinom.charAt(i+1);
else{
if(polinom.charAt(i)=='^' && i < polinom.length() - 1){ // same
v=Integer.parseInt(Character.toString(polinom.charAt(i+1)));
coef1[v]=-Integer.parseInt(Character.toString(c));
System.out.print(coef1[v]);
}
}
}
In the second line here you are using
for(i=0;i<polinom.length()+1;i++){
That +1 should be -1.
I suppose the variable polinom is a String.
Your're looping beyond the end of the string:
for(i=0;i<polinom.length()+1;i++)
It should be
for(i=0;i<polinom.length()-1;i++)
I have to trim (including whitespaces within the string) all the strings in a list. I have written a method to do this trim using regex. I am using strArray[i] = trimString(strArray[i]); instead of using an enhanced for loop. I assume since string is immutable this way of assigning back to the same array element is correct. Am I right?
public void trimStringArray(String[] strArray){
if(strArray!= null && strArray.length > 0){
for(int i=0;i<strArray.length;i++){
strArray[i] = trimString(strArray[i]);
}
}
}
Yes, that's fine, and you wouldn't be able to use the enhanced for loop. However, you can simplify your code by getting rid of the length > 0 check - there's no harm in it executing the loop 0 times... and personally I would usually expect the parameter to such a method to be non-null anyway, leading to code like this:
public void trimStringArray(String[] strArray) {
Preconditions.checkNotNull(strArray);
for(int i = 0; i < strArray.length; i++) {
strArray[i] = trimString(strArray[i]);
}
}
(Preconditions.checkNotNull comes from Guava in this case.)
You could leave it accepting null - but do you really have many situations where it's valid to have a null array, but you want to trim everything if it's not?
As a readability thing, I'd also encourage you to include a bit more whitespace - it's definitely a personal preference, but I know I find code with no spaces, such as this, harder to read:
for(int i=0;i<strArray.length;i++){
Yes, your code is correct.
Note that the strArray.length > 0 check is redundant: the loop condition will automatically take care of the case when strArray has zero length.
Yes, it is ok to do. I would add add final in method signature. By adding final you can make sure mistakenly you are not re-assigning references (added safety).
public void trimStringArray(final String[] strArray){