Java string value change in function - java

I have this very awkward question...
void changeString(String str){
str = "Hello world":
}
main(){
String myStr = new String("");
changeString(myStr);
}
When main returns, the value is still "" and not "Hello world". Why is that?
Also, how do I make it work? Let's say I want my function changeString to change the string it got to "Hello world".

Everyone explained why it doesn't work, but nobody explained how to make it work. Your easiest option is to use:
String changeString() {
return "Hello world";
}
main() {
String myStr = new String("");
myStr = changeString();
}
Although the method name is a misnomer here. If you were to use your original idea, you'd need something like:
void changeString(ChangeableString str) {
str.changeTo("Hello world");
}
main() {
ChangeableString myStr = new ChangeableString("");
changeString(myStr);
}
Your ChangeableString class could be something like this:
class ChangeableString {
String str;
public ChangeableString(String str) {
this.str = str;
}
public void changeTo(String newStr) {
str = newStr;
}
public String toString() {
return str;
}
}
A quick lesson on references:
In Java method everything is passed by value. This includes references. This can be illustrated by these two different methods:
void doNothing(Thing obj) {
obj = new Something();
}
void doSomething(Thing obj) {
obj.changeMe();
}
If you call doNothing(obj) from main() (or anywhere for that matter), obj won't be changed in the callee because doNothing creates a new Thing and assigns that new reference to obj in the scope of the method.
On the other hand, in doSomething you are calling obj.changeMe(), and that dereferences obj - which was passed by value - and changes it.

Java uses a call by value startegy for evaluating calls.
That is, the value is copied to str, so if you assign to str that doesn't change the original value.

If the changing of your String happens very often you could also assign a StringBuffer or StringBuilder to your variable and change its contents and only convert it to a String when this is needed.

Expanding a bit on NullUserException's excellent answer, here's a more general solution:
public class Changeable<T> {
T value;
public Changeable(T value) {
this.value = value;
}
public String toString() {
return value.toString();
}
public boolean equals(Object other) {
if (other instanceof Changeable) {
return value.equals(((Changeable)other).value);
} else {
return value.equals(other);
}
}
public int hashCode() {
return value.hashCode();
}
}
Yura's original code can then be rewritten as:
void changeString(Changeable<String> str){
str.value = "Hello world":
}
void main() {
Changeable<String> myStr = new Changeable<String>("");
changeString(myStr);
}
And, just for fun, here it is in Scala:
class Changeable[T](var self: T) extends Proxy;
object Application {
def changeString(str: Changeable[String]): Unit = {
str.self = "Hello world";
}
def main(): Unit = {
val myStr = new Changeable("");
changeString(myStr);
}
}

Because the reference myStr is passed by value to the function changeString and the change is not reflected back to the calling function.
P.S : I am not a Java guy.

Bill, I have a solution to your problem which uses a List as a pointer in java!
void changeString(List<String> strPointer ){
String str = "Hello world";
strPointer.add(0, str);
}
main(){
LinkedList<String> list = new LinkedList<String>();
String myStr = new String("");
changeString(list);
myStr = list.get(0);
System.out.println( myStr );
}
This answer takes a little extra work to insert and get out the string from the list, however the final line will print "Hello world!"
I hope this can help others as well!
-Port Forward Podcast

Here's the one more solution by StringBuffer/StringBuilder worked for me.
static void changeValue(StringBuilder str){
str.append("newValue");
}
main(){
StringBuilder originalVal= new StringBuilder();
changeValue(originalVal);
System.out.println(originalVal.toString());
}

Related

Return multiple variables from single method with different data types in java

I am new at java . I have method witch contain some variables with different data type i.e. String and Array
pNumber=rs.getString("pNumber");
userName=rs.getString("userName");
simOperater=rs.getString("simOperater");
AdharNumber=rs.getString("AdharNumber");
rechargeAmount[i]=rs.getString("rechargeAmount");
activeDate[i]=rs.getString("activeDate");
plainDeatils[i]=rs.getString("plainDeatils");
and I want to return all the variables from single method in java so what approach should I use please help
just return a response object
public class MyResponse {
public String pNumber;
public String userName;
//....
}
usage:
public MyResponse yourMethod() {
MyResponse myResponse = new MyResponse();
myResponse.pNumber=rs.getString("pNumber");
myResponse.userName=rs.getString("userName");
//...
return myResponse;
}
If you don't want to write more lines, you can also set the return type of your method to Object and return your variable as you normally would, but then cast the returned object into the right type as it was before.
e.g.
class test {
static Object test_return(int which) {
String s = "This is a string";
int i = 100;
if(which == 0) {
return s;
} else {
return i;
}
}
public static void main(String args[]) {
String s = (String) test_return(0);
int i = (int) test_return(1);
System.out.println("String: " + s + "\nint: " + i);
}
}
output:
String: This is a string
int: 100
edit:
since you are new to java, you might not understand how types exactly work here. so I would suggest you read this and this to learn more about autoboxing and unboxing

How would I get a string from a different method if they are in the same class

Right, I understand that this question has more than likely been answered before however it won't work in my circumstance.
So I have a string that I need to get into another method, here's the code...
public String createColoredMinuses(int amount, ChatColor colorOne, ChatColor colorTwo)
{
StringBuilder builder = new StringBuilder();
builder.append(amount < 13);
if (amount % 2 == 0) {}
builder.append(ChatColor.BLUE + "-");
builder.append(ChatColor.DARK_BLUE + "-");
String string = builder.toString();
return string;
}
public boolean onCommand(CommandSender sender, Command cmd, String command, String[] args)
{
public static void createColoredMinuses()
{
Method1();
}
String b = builder.toString();
So what I want to happen is I want to be able to get the 'return string;' into the main part where all the commands go but into the 'String b=' part however I can't work out how to do it.
I hope this made sense to you! :P
Would it not be enough to have the builder as a private variable? I mean you literally want to use it privately in another method that you call later:
private StringBuilder builder = new StringBuilder();
public String createColoredMinuses(int amount, ChatColor colorOne, ChatColor colorTwo)
{
builder.append(amount < 13);
if (amount % 2 == 0) {}
builder.append(ChatColor.BLUE + "-");
builder.append(ChatColor.DARK_BLUE + "-");
String string = builder.toString();
return string;
}
public boolean onCommand(CommandSender sender, Command cmd, String command, String[] args) {
public static void createColoredMinuses ()
{
Method1();
}
String b = builder.toString();
}
Another noticeable thing is that you have this method:
public static void createColoredMinuses ()
{
Method1();
}
And it's inside the onCommand... this doesn't look right. You need to move this to somewhere else.
In the end, I just moved the StringBuilder as I couldn't work out how to call the method.
So that it was in the class with everything else.

Encapsulation for Reference Variables?

It may be a common question but I couldn't find nice explanation for it. I am trying to understand the encapsulation of reference variables in Java.In the below code:
class Special {
private StringBuilder s = new StringBuilder("bob");
StringBuilder getName() { return s; }
void printName() { System.out.println(s); }
}
public class TestSpecial {
public static void main (String[] args ) {
Special sp = new Special();
StringBuilder s2 = sp.getName();
s2.append("fred");
sp.printName();
}
}
Output: bobfred
At first I thought making our field private and providing a getter method, it's a good encapsulation technique. But when I took closer look on it, I saw that when I invoke getName(), I do in fact return a copy, just like Java always does. But, I am not returning a copy of the StringBuilder object. I am returning a copy of the reference variable that point to the one and only StringBuilder object. So, at the point that getName() returns, I have one StringBuilder object and two reference variables pointing to it ( s and s2).
What are the techniques to make it well encapsulated?? A good explanation with code example expected :) . Thanks in advance.
There are two basic approaches I can think of.
The first is to only return immutable values. The caller can then do what he wants without risking the integrity of your object. In your case, the immutable type would be String:
class Special {
private String s = "bob";
String getName() { return s; }
void printName() { System.out.println(s); }
}
public class TestSpecial {
public static void main (String[] args ) {
Special sp = new Special();
String s2 = sp.getName();
s2 += "fred";
// Alternatively: StringBuilder s2 = new StringBuilder(sp.getName()).append("fred");
sp.printName(); // prints "bob"
}
}
Note: If s needs to be a StringBuilder, you can return s.toString().
The other option is to return a mutable value, but create a defensive copy in your getter. In other words, return a separate reference with duplicate data:
class Special {
private StringBuilder s = new StringBuilder("bob");
StringBuilder getName() { return new StringBuilder(s); } // return a copy of s
void printName() { System.out.println(s); }
}
public class TestSpecial {
public static void main (String[] args ) {
Special sp = new Special();
StringBuilder s2 = sp.getName();
s2.append("fred");
sp.printName(); // prints "bob"
}
}
There can be multiple ways to apply encapsulation to mutable object.
By providing copy constructor (in above example new StringBuilder(oldBuilder.toString())
public class Student{
private String name;
public Student(Student s){
this.name = s.name;
}
}
Using prototype pattern with clone method. But copy Constructor is recommend over clone method.
public Student implements Cloneable{
private int rollNo;
private String name;
public Student clone(){
Student s = (Student)super.clone();
s.name = this.name;
s.rollNo = this.rollNo;
return s;
}
}
public class Clazz{
private Map students= new HashMap();
public student getStudent(int rollNo){
Student s = students.get(rollNo);
return s.clone();
}
}
Using immutable form of mutable object. e.g. Collections.unmodifiablecollection().
Whenever we return collection or array, always return read-only form. So modifications to collection will not impact the state of the object.

java String variables not setting

This is a much simplified version of a class file I'm working on, I've just used these classes to show my problem.
public class Test {
private String string1 = null;
private String string2 = null;
private void setString(String s) {
s = "hello";
}
private void set() {
setString(string1);
setString(string2);
}
public void print() {
System.out.println(string1);
System.out.println(string2);
}
public void initialise() {
set();
print();
}
}
public class StringTest {
public static void main(String[] args) {
Test test = new Test();
test.initialise();
}
}
Anyway, basically, after this the two string variables are still null. What causes this problem? and how can I get around it? (Still learning the fundamentals of java - if that's relevant).
Any help/guidance is greatly appreciated.
Because a String is immutable, any change you make inside the method will be local to that method.
private void setString(String s) {
s = "hello";
}
s can't be changed.
I can think of two options.
Option 1
Make s an instance variable (field) and change your method.
public class Test {
private String string1 = null;
private String string2 = null;
private String s;
private void setString(String s) {
this.s = "hello";
}
Option 2
Pass in a StringBuilder/StringBuffer instead of String.
Your problem is that Java is pass by value, so your setString method does not do anything. To change the value of string1, you need to have string1 = xxxx; somewhere in your code. For example:
private void set() {
string1 = getDefaultString();
string2 = getDefaultString();
}
private String getDefaultString() {
return "hello";
}
You are setting the value of "s" not string1 or string2
try something like.
private void setString(String s) {
string1 = "hello";
string2 = "world";
}
By making this assignation
s = "hello";
weare creating a new object. It will have a different memory address than the one passed with setString(string1);
We would need to change the object received at
private void setString(StringBuilder s) { ... }
instead of creating a new one. We need to use exactly the same object we were passed in this method. Can't create a new one, as the caller method wouldn't notice (parameters in Java are never output parameters).
As Java's String is inmutable, we can't change its content: just create a new String object.
As #adarshr pointed out, we can use StringBuilder or StringBuffer, which are mutable, and change their content. But we can't just replace String with StringBuilderin you code. We have to make sure that:
The StringBuilder is initialized before being passed to setString().
The StringBuilder is not created again inside setString() (we are using the same one we were passed).
So, replacing this in your code should work:
private StringBuilder string1 = new StringBuilder();
private StringBuilder string2 = new StringBuilder();
private void setString(StringBuilder s) {
s.append("hello");
}
you misunderstand of java parameter passing, try public void setString1(String s) { string1 = s; }
What are you trying to initialize the values of string1 and string2 to? The two member variables start out being null.
If I were to treat Test class as a POJO (plain old Java object), I would add getter/setter methods as follows:
public class Test {
private String string1;
private String string2;
public String getString1() {
return this.string1;
}
public String getString2() {
return this.string2;
}
public void setString1(String s) {
this.string1 = s;
}
public void setString2(String s) {
this.string2 = s;
}
/*
* Additional methods
*/
public void set() {
setString1("hello");
setString2("world");
}
public void print() {
System.out.println(this.string1);
System.out.println(this.string2);
}
public void initialize() {
set();
print();
}
}
ur application is assigning the hello word in parameter s..but the variable s is a parameter type thats y the reflection of s will be in setString() method block...not anywhere else...use instance variable or static variable to see the reflection of ur assignment.

Can I change String object's value passed to my method?

I found the following question Is Java "pass-by-reference" or "pass-by-value"?.
I read almost all of it, but could not find out yet what should I do if I want the foo(-) method, to change my String's value? (maybe or not reference too, it doesn't matter to me).
void foo(String errorText){
errorText="bla bla";
}
int main(){
String error="initial";
foo(error);
System.out.println(error);
}
I want to see bla bla on the console. Is it possible?
You can't change the value of errorText in foo as the method is currently declared. Even though you are passing a reference of the String errorText into foo, Java Strings are immutable--you can't change them.
However, you could use a StringBuffer (or StringBuilder). These classes can be edited in your foo method.
public class Test {
public static void foo(StringBuilder errorText){
errorText.delete(0, errorText.length());
errorText.append("bla bla");
}
public static void main(String[] args) {
StringBuilder error=new StringBuilder("initial");
foo(error);
System.out.println(error);
}
}
Other solutions are to use a wrapper class (create a class to hold your String reference, and change the reference in foo), or just return the string.
Either use the return value of the method or create a wrapper class.
Have it return the value:
String foo(String errorText){
return "bla bla";
}
int main(){
String error="initial";
error = foo(error);
System.out.println(error);
}
Wrap the value in an object:
class StringWrapper {
private String string;
public StringWrapper(String s) {
this.string = s;
}
public String getString() {
return this.string;
}
public void setString(String s) {
this.string = s;
}
}
void foo(StringWrapper errorText){
errorText.setString("bla bla");
}
int main(){
StringWrapper error=new StringWrapper("initial");
foo(error);
System.out.println(error.getString());
}
Yes you can change this with help of reflections but its against rule.
void foo(String errorText) {
try {
final Class<String> type = String.class;
final java.lang.reflect.Field valueField = type.getDeclaredField("value");
valueField.setAccessible(true);
valueField.set(errorText, "bla bla".toCharArray());
} catch (Exception e) {
}
}
public static void main(String[] args) {
String error = new String("initial");
foo(error);
System.out.println(error);
}
String values are immutable -- so once you get a value, you're stuck with it.
Literal Strings are treated specially by the Java language; your code is roughly equivalent to:
void foo(String errorText){ // at this point, errorText refers to the original string
errorText=new String("bla bla"); // now it refers to a new string
}
int main(){
String error=new String("initial"); // error is a reference to the original string
foo(error); // pass a *copy* of the reference
System.out.println(error);
}
In other words, you're just pointing the local reference errorText at a different String object, which affects nothing outside the method.
More generally, though, Strings are immutable; there's no way to modify them.
You can reassign the String reference:
String foo(String err) {
return "bla blah"
}
error = foo(error);

Categories