0

I'm a beginner programmer and I'm trying to make a very simple version of Hangman. I'm having so problem with my code. This is the portion of code I'm having a problem with:

        for(int i = 0; i <= wordLength - 1; i++ ) {

            if (letter == theWord.charAt( i )) {

                onemore=i+1;
                System.out.println("This letter matches with letter number " + onemore + " in the word.");
                ***displayWord.charAt(i)=letter;***
                System.out.println("The word so far is " + displayWord);
            } 

        }

The part I'm getting an error with has 3 asterisks on either side of it.

displayWord is a String and letter is a char.

Netbeans tells me:

unexpected type
  required: variable
  found:    value

I have no idea what the problem is.

tshepang
  • 12,111
  • 21
  • 91
  • 136
Rohan Khajuria
  • 636
  • 2
  • 12
  • 26
  • Maybe I should have elaborated. When you have `displayWord.charAt()`, its equivalent to saying a single character. Of course, thats what it results to, but not what we see. So in your case, I assume you didn't want to say `'c' = 'd'`, because it doesn't really do anything. But what you wanted was to put `letter` into the index of whatever String `displayWord` represented. The problem is that can never even happen because `displayWord.charAt()` isn't actually a String perse, but rather a character after the statement is evaluated. Does that make sense? – Andy Aug 09 '12 at 03:58

4 Answers4

4

Basically, Java Strings are immutable, that is, there contents can't be changed.

You'd be better of using a StringBuilder.

String theWord = "This is a simple test";
char letter = 'i';
char changeTo = '-';

StringBuilder displayWord = new StringBuilder(theWord);

int i = theWord.indexOf(letter);
if (i != -1) {
    System.out.println("This letter matches with letter number " + (i + 1) + " in the word.");
    displayWord.setCharAt(i, changeTo);

    System.out.println("The word so far is " + displayWord);
}

System.out.println(displayWord);

This results in:

This letter matches with letter number 3 in the word.
The word so far is Th-s is a simple test
This letter matches with letter number 6 in the word.
The word so far is Th-s -s a simple test
This letter matches with letter number 12 in the word.
The word so far is Th-s -s a s-mple test
Th-s -s a s-mple test

Now the short version might look something like

String displayWord = theWord.repace(letter, changeTo);
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • 2
    Great explanation. If it helps, think of it this way, what does `displayWord.charAt()` return? Its a character. Now imagine you used that character instead of using `displayWord.charAt()`. Would saying i dont know, something like `'c' = 'd';` make any sense for what you are trying to do? It helps to replace the statement you have with what you are expecting it to have, and sort of go from there. Hopefully that advice helps you understand where other issues you may have come from. – Andy Aug 09 '12 at 03:32
  • @Andy What do you mean by " It helps to replace the statement you have with what you are expecting it to have, and sort of go from there.? – Rohan Khajuria Aug 09 '12 at 03:38
  • Could you give me an example? – Rohan Khajuria Aug 09 '12 at 03:38
  • Oops. For some reason Chrome didn't load all of Mad Programmers reply. I now understand what to do. Thank you :) – Rohan Khajuria Aug 09 '12 at 03:44
  • @veer I'm curious as to the change - I only ask because the OP was using a loop to loop through the theWord variable – MadProgrammer Aug 09 '12 at 04:00
  • @MadProgrammer I was tired and not paying attention :p – obataku Aug 09 '12 at 04:28
  • @veer no probs, been there, just thought I missed something ;) – MadProgrammer Aug 09 '12 at 04:29
  • I'm having another problem. I write: "StringBuilder displayWord = new StringBuilder(theWord);". At this I get an error saying "displayWord is already defined in main(java.lang.String[])". Please help me. – Rohan Khajuria Aug 18 '12 at 01:46
  • @user1218257 Change the variable name. You can't use the same variable name for a different type. Try `StringBuilder sbDisplayWord = new StringBuilder(theWord);` – MadProgrammer Aug 18 '12 at 02:29
  • After I change it to :"StringBuilder sbdisplayWord = new StringBuilder(theWord);" do I also have to change anything else? – Rohan Khajuria Aug 22 '12 at 04:22
  • @user1218257 I shouldn't think so, but I'm not aware of your recent code changes ;) – MadProgrammer Aug 22 '12 at 05:03
  • I'm having another problem in which I type " displayWord.setCharAt(i, letter);" and in which I get an error where it says "cannot find symbol" – Rohan Khajuria Aug 22 '12 at 23:46
  • Sorry, don't have eyes on your code :P - Try changing `displayWord` to `sbDisplayWord`. Once you're finished with with the `StringBuffer` use the `.toString` method to get the resulting value – MadProgrammer Aug 23 '12 at 00:53
0

I'm not sure about that error, but in Java you can't update the character in a style like that.

Instead, try using StringBuilder for your displayWord. That has a method: setCharAt that might be what you want.

Good luck coding :)

Michael
  • 1,014
  • 1
  • 8
  • 23
  • 1
    `StringBuffer` is fully `synchronized`... perhaps you meant `StringBuilder`? It avoids the overhead. – obataku Aug 09 '12 at 03:28
  • Depends what you're going for. I tend not to use StringBuilder from enterprise experience, plus there's comments in general about the performance of both. – Michael Aug 09 '12 at 03:30
  • 1
    Well there should be no reason to use `StringBuffer` unless you intend to be accessing it concurrently. Since I don't think there's any such access in his Hangman game, the `synchonized` is unnecessary. If the VM is intelligent enough, it can avoid most of the overhead by first checking if the lock could possibly be contended, so performance might turn out comparable... I wasn't intending to advocate premature optimization, just suggesting an alternative :p – obataku Aug 09 '12 at 03:35
  • 1
    Indeed :) I took that one in stride! I should probably use Buffer less in my normal uses... Unless tbh, I am getting that confused and misremembering. Maybe I do use Builder. That's actually more likely. Bit of a fail. Anyway! Get them started on concurrency nice & early. Bound to save problems later ;) – Michael Aug 09 '12 at 03:37
  • @TehHippo I can assure you that in more than 99% of case where StringBuffer is used StringBuilder is a better choice. In the classes where StringBuffer was used in the JDK, the classes are not thread safe. – Peter Lawrey Aug 13 '12 at 08:07
  • Updated my answer now; I found I just got confused, most of my code has the great builder in there. Just got confused. :P – Michael Aug 13 '12 at 22:39
0

charAt(i) RETURNS the value of the letter at that part of the word, you can't use it to CHANGE the value. Strings in Java are immutable, so you actually can't change this one. You can create a new one (using a constructor or possible one of the replaceXXX functions) and assign it back to displayWord, or take a look at the StringBuffer class which is more efficient for this type of thing.

Jim O'Neil
  • 23,344
  • 7
  • 42
  • 67
  • I think for what I'm doing, StringBuilder would be more efficient (first comment). But thanks anyway. I will probably use String Buffer for something else. – Rohan Khajuria Aug 09 '12 at 03:45
0

Since String is an immutable object, you can't change its content. Immutable means that once the content of the String is set, you don't have the ability of changing it in any way. You can always change the reference but never the content itself.

That being said, the String object doesn't offer any method to violate this principle. There's no setCharAt and you can't assign a new value to the result of charAt(i). Note how some methods that "seem" to change the String (like replace) are instead returning a new cloned object with changes on it. For example:

String sample = "Hello World!";
sample.replace('e', '*');
System.out.println(sample);

The above code is not making any changes on sample, so the result printed on the screen will be Hello World!. In order to capture the changes made by the replace method, we need to reassign the sample variable to the result of replace:

String sample = "Hello World!";
sample = sample.replace('e', '*');
System.out.println(sample);

In this case we are updating our sample variable with the new cloned String returned by replace. This value will have the changes, so we are going to see H*llo World! printed out.

Now that you know why you can't change the content of your Strings, let's see what solutions you have.

  1. First and foremost, to keep the exact behavior of your program, the perfect way to go is using a StringBuilder like @MadProgrammer pointed out before. An over simplistic way of looking at the StringBuilder class is basically as a mutable String. With it you can do all kind of replacements and modifications.

  2. Another solution (and not recommended) is to play with the String to create a new copy every time you want to change a character. This is going to be really cumbersome and offers no advantages over the StringBuilder solution, so I'm not going to go over the details.

  3. The third solution depends on your requirements and how flexible you can be. If all that you want to do is to replace every occurrence of a certain character in your String, then your code can be simplified a lot and you can use the replace method I talked about before. It will be something like:

    String theWord = "Here is our testing string"; char letter = 'e'; char changeTo = '*'; String displayWord = theWord.replace(letter, changeTo); System.out.println("The resulting word is: " + displayWord);

This will output the following result:

The resulting word is: H*r* is our t*sting string

Again, this only works in case your requirements are flexible enough and you can skip the "step by step" approach you are following in your example code.

svpino
  • 1,864
  • 17
  • 18