Closures in Java & immutable Strings. How does this program work? - java

Here is the program
public class Closure {
public String foo = "";
public static Closure process(final Closure t) {
System.out.println(t.toString() + " = " + t.foo);
t.foo = "bar";
new Runnable() {
public void run() {
System.out.println(t.toString() + " = " + t.foo);
t.foo = "baz";
}
}.run();
System.out.println(t.toString() + " = " + t.foo);
return t;
}
public static void main(String[] args) {
process(new Closure());
}
}
When I execute it, all 3 prints show the same reference for the variable t.foo. This makes sense for Closures, it is as we expect it.
What puzzles me is that in Java Strings are immutable. So if we reassign the string, shouldn't the reference change?

It is a little confusing to be using Closure when the question doesn't contain any closures.
The output of your program should look like (Ideone wants a class with this name instead of Closure)
Ideone#1e61582 =
Ideone#1e61582 = bar
Ideone#1e61582 = baz
see http://ideone.com/c5HzEF
As you can see the reference foo is changing. The reference t which is what you print, doesn't change as expected.

The foo property is a reference. This is a misunderstanding of what it means for a string to be immutable in Java.
See Immutability of Strings in Java

No, because you print the reference of the Closure object, not of the String.

Related

final keyword when passing an instance of java.lang.Number to a method

I was thinking about is there any sense to use final keyword in a method signature when passing an instance of java.lang.Number (ex. java.lang.Long)?
I think that it does not make any sense because java pass object reverences by value. That means java passes a copy of the original reference to the method. Any changes in value on this Number is invisible outside of the method. So it does not matter if the method changes or not the value inside the method.
Of course when we pass a pojo to a method then it makes sense to use the final keyword but it is a different scenario.
java.lang.Number demo
public class Demo {
public static void main(String[] args) {
Long longValue = 1L;
System.out.println("Long before: " + longValue);
System.out.println(trickyMethod(longValue));
System.out.println("Long after: " + longValue);
BigInteger bigIntegerValue = BigInteger.ONE;
System.out.println("BigInteger before: "+ bigIntegerValue);
System.out.println(trickyMethod(bigIntegerValue));
System.out.println("BigInteger after: " + bigIntegerValue);
}
private static String trickyMethod(Long value) {
value = 10L;
System.out.println(" trickyMethod: " + value);
if (value.equals(10L))
return " equal";
else
return " different";
}
private static String trickyMethod(BigInteger value) {
value = BigInteger.TEN;
System.out.println(" trickyMethod: " + value);
if (value.equals(BigInteger.TEN))
return " equal";
else
return " different";
}
}
And the output
Long before: 1
trickyMethod: 10
equal
Long after: 1
BigInteger before: 1
trickyMethod: 10
equal
BigInteger after: 1
POJO demo
public class Demo {
static class Container {
private Long l;
public Container(Long l) {
this.l = l;
}
#Override
public String toString() {
return String.valueOf(l);
}
#Override
public boolean equals(Object obj) {
Container c = (Container) obj;
return l.equals(c.l);
}
}
public static void main(String[] args) {
Container container = new Container(1L);
System.out.println("Container before: "+ container);
System.out.println(trickyMethod(container));
System.out.println("Container after: " + container);
}
private static String trickyMethod(final Container container) {
container.l = 10L;
System.out.println(" trickyMethod: " + container);
if (container.equals(new Container(10L)))
return " equal";
else
return " different";
}
}
And the output
Container before: 1
trickyMethod: 10
equal
Container after: 10
Why developers use final keywords in method signature like this String method(final Long value) in case of Long?
It doesn't matter ever, whether the parameter is immutable or not. A final mutable parameter can be modified internally, you just can't reassign anything to the parameter variable.
One of the more useless things in Java, it would be nice if the parameters were implicitly final, as it's a code smell if you're reassigning a parameter. Most code analyzers report it as a bug/warning/etc.
The basic rule of thumb is, unless syntactically required to make the parameter final (in very rare cases), don't bother putting final in the parameters since it will just create useless clutter in the code. However never reassign parameters, as it can be bug-prone, and pretend that all parameters are final.
the reason why developers use the following is simply to prevent the variable from being re-assigned.
e.g
void method(final long value){
long number = 90;
value = number; // COMPILER ERROR
}
So, I guess if you don't want to accidently reassign it later on when reassigning it will result in it bad situation then you can declare it as final.
All of the java.lang package wrapper classes are immutable. That includes String, Long, Double etc. Hence you are correct that it doesn't matter if we mark them final. But remember that in your example you are reassigning value reference. In case of say StringBuilder, that would be new object reference.
But you are right, doesn't matter in case of immutable objects.

Immutability of string objects in java

I'm noob in programming, now learning Java.
I have read that Strings are immutable in Java. But, I have a question regarding it.
public class Immutable {
public static void main (String[ ] args)
{
new Immutable().run();
} // method main
public void run()
{
String s = "yEs";
String p = "Do";
p=p.toUpperCase();
s=s.toLowerCase();
//Here above I'm able to change the content of the string object.
//Why is it said Immutable??
p = new String("DoPe");
System.out.println(p);
// Here I'm taking it as I'm creating new object and I'm assigning it to 'p'
//rather than changing the previously assigned object. so it's immutable
//Is my understanding correct??
flip (s);
System.out.println(s);
//Why does assigning a new object using a method doesn't work
//while if I do it explicitly, it works(as I've done for 'p', see above)
} // method run
public void flip (String t)
{
System.out.println(t);
t = new String ("no");
System.out.println(t);
t = "nope";
System.out.println(t);
} // method flip
} // class Immutable
Please see questions in my comments.
Revision:
public class Immutable {
public static void main (String[] args)
{
new Immutable().run();
} // method main
public void run()
{
String s = "yEs";
String p = "Do";
int [] arr = new int[5];
for (int i = 0; i < 5; i++)
arr[i] = i;
System.out.println("Value in the calling function before the altering is done: "+Arrays.toString(arr));
alter(arr);
System.out.println("Value in the calling function after the altering is done: "+Arrays.toString(arr));
p = p.toUpperCase();
s = s.toLowerCase();
//Here above I'm able to change the content of the string object.
//Why is it said Immutable??
p = new String("DoPe");
System.out.println(p);
// Here I'm taking it as I'm creating new object and I'm assigning it to 'p'
//rather than changing the previously assigned object. so it's immutable
//Is my understanding correct??
System.out.println("Value of string in the calling function before the altering is done: "+s);
flip (s);
System.out.println("Value of string in the calling function after the altering is done: "+s);
//Why does assigning a new object using a method doesn't work
//while if I do it explicitly work(as I've done for 'p', see above)
} // method run
public void flip (String t)
{
System.out.println("Value of string in the called function, before altering: "+t);
t = new String ("no");
System.out.println("Value of string in the called function, after Altering: "+t);
t = "nope";
System.out.println(t);
} // method flip
public void alter(int[] a)
{
System.out.println("Value in the called function, before altering: "+Arrays.toString(a));
a[3] = 50;
System.out.println("Value in the called function, after Altering: "+Arrays.toString(a));
}
} // class Immutable
Modification works for arrays, but not for strings.
Is this the reason strings are called immutable??
Am I missing something?
Here above I'm able to change the content of the string object. Why is it said Immutable??
You don't change the contents of the String, you create a new String object and link it with the variable, the old object will be removed.
Here I'm taking it as I'm creating new object and I'm assigning it to 'p' rather than changing the previously assigned object. so it's immutable. Is my understanding correct??
Yes, and this is actually the same you did one question above, but the String object was created by one of its instance methods.
Why does assigning a new object using a method doesn't work while if I do it explicitly work(as I've done for 'p', see above)
This is because the immutability of String. Java is pass-by-value, but your method needs to be pass-by-pointer. Since you can't change the contents of the String (you only can create a new String object), you'll need to return the String.
You're not changing the content of the string object, you're changing which variable point to which object in memory.
Variables are just pointers to the objects in memory, not the actual objects.
You're not changing the content of the string objects. You're creating new objects and making s and p point to the new objects.
//Here above I'm able to change the content of the string object.
//Why is it said Immutable??
You did not change the content of the string, you simply created a new String and assigned its reference to your String variable. That also answers to your second comment.
//Why does assigning a new object using a method doesn't work
//while if I do it explicitly work(as I've done for 'p', see above)
Because Java methods are not pass-by-reference. See this question for further information.
I believe you are making confusion about things.
Overall, I do understand what you mean.
You believe that you "changed" p by p = new String("DoPe"); which is let's say correct but the same thing doesn't happen with s when you call flip (s);
Well, calling it won't "change" s because your function flip only takes a string and modifies it internally and that's it.
In order to "change" s using a function you have to do this modifications:
1 s= flip (s);
(s receives the returned value of the function)
2. Function flip should return a String and not a void
public String flip (String t) // String instead of void
{
System.out.println(t);
t = new String ("no");
System.out.println(t);
t = "nope";
System.out.println(t);
return t; //returns the String t
}

The type of the object created with a help of Object o = "";

Say, there is a following example:
class Super {
public int i = 3;
public void m(Object o) {
System.out.println("Object " + i);
}
public void m(String o) {
System.out.println("String " + i);
}
}
public class Sub extends Super {
public Sub() {
i = 5;
}
public static void main(String[] args) {
Super s = new Sub();
Object o = "";
s.m(o);
s.m("");
}
}
The result of this code is:
Object 5
String 5
But I thought it would be:
String 5
String 5
Don't quotes set String as this object's type? There are definitely some cases of casting to String with a help of quotes, so I'm a little confused about this basic example. Thanks in advance.
The type of the method is determined in compile time, and not in run time. The dynamic dispatch exists only for the "parameter" this - there is no dynamic dispatch for parameters in static typing languages such as java.
The compiler "choses" which method should be invoked, and since o is of type Object - it choses m(Object) - it has no way to know that the dynamic type of o is actually a String.
If you are interested - a common way to overcome this issue in some cases is using the visitor design pattern.
In your specific case, in order to "force" the activation of m(String) you should use m(o.toString())
In sb.m(o), you're calling m() with an Object reference, so Java chooses that overload. Java will not choose a more specific overload than the reference type you pass it. It will go up the inheritance chain though. Say you didn't have m(String o), calling sb.m("Hello") would still be legal, but it would call the object version.
If you were to do sb.m((String) o), you would get your expected behavior.
You declared the object as Object so its type is Object. Types in Java are strong and static so when you declare an object as type Type that is what its type will be for life.
If you want it to be a string you'll have to use a toString method or a cast (String)o
You are downcasting the String to an Object. What you are doing is similar to this.
public class Sub extends Super {
public Sub() {
i = 5;
}
public static void main(String[] args) {
Super s = new Sub();
Object o = "";
System.out.println("Object Type = " + o.getClass().getName());
s.m(o);
s.m((Object)"");
}
}

Possible to prevent Java's pass by value in methods?

Java is a 'pass by value' language, meaning that sending in a variable into a method, pointing the variable to a new object, does not effect the outer variable.
public void one() {
String s = "one";
two(s);
System.out.println(s);
}
public void two( String s ) {
s = "two";
}
Would write "one".
Is there a way to prevent this? Or what is the most common solution or pattern to actually change s to "two" inside the method?
Is not possible to prevent it.
You can emulate it with a generic wrapper like this:
class _<T>{
public T _;
public _(T t ) {
_ = t;
}
public String toString(){ return _.toString(); }
}
And then use it as you intended.
class GeneriWrapperDemo {
public static void main(String [] args ) {
_<String> one = new _<String>("One");
two( one );
System.out.println( one );
}
public static void two( _<String> s ) {
s._ = "two";
}
}
But looks ugly. I think the best would be to change the reference it self:
public String two( String a ) {
return "two";
}
And use it
String one = "one";
one = two( one );
:)
You can't pass-by-reference - at least not the variable itself. All parameters are passed by value. However, objects contain references - and are represented as references themselves. You can always change the insides of the object, and have the changes stick. Thus, send an array, or create a wrapper class, or make your own reference object:
class Ref<T> {
T obj;
public Ref(T value) {
this.obj = value;
}
public void set(T value) {
obj = value;
}
public T get() {
return obj;
}
}
As the others have said, String is not mutable anyway, so you're not actually changing the string here, but making the variable point the other way, so it does not really make that much sense not to simply return the new string.
If s were a mutable object, you could change its value (i.e. the value of its data members). And the member can be a String too. This doesn't work with a String parameter directly, as it is immutable, so the only way to "change" it is to direct the reference to a different object.
Create an object, which contains the string, then pass that into the method.
public class StringHolder {
public String s;
public StringHolder(String s) {
this.s = s;
}
}
Then the code would look like:
public void two(StringHolder sh) {
sh.s = "two";
}
StringHolder sh = new StringHolder("one");
two(sh);
System.out.println(sh.s);
Although, for the above example, you could just return the value you want:
public String two(String s) {
return "two";
}
String s = "one";
s = two(s);
System.out.println(s);
And for Strings, you can always use StringBuffer, which is mutable:
public void two(StringBuffer buf) {
buf.setLength(0);
buf.append("two");
}
You can't prevent Java from passing by value; that's the language semantics.
You can, one way or another, get around it, depending on what you want to do.
You can return a new value based on the parameter that's passed:
static String scramble(String s) {
return s.replaceAll("(.*) (.*)", "$2, $1");
}
// then later...
String s = "james bond";
s = scramble(s);
System.out.println(s); // prints "bond, james"
You can also pass something that is mutable:
static void scramble(StringBuilder sb) {
int p = sb.indexOf(" ");
sb.append(", ").append(sb.substring(0, p)).delete(0, p+1);
}
// then later...
StringBuilder sb = new StringBuilder("james bond");
scramble(sb);
System.out.println(sb); // prints "bond, james"
Strings are immutable... otherwise, though, all you would have to do is call a method to operate on the same object and have that somehow change the string value.
I'm sure there are a number of Java classes that will do the job for you, but you could also roll your own simply by creating an encapsulating class with either a public field or a setter/getter. An example of the former is something like this:
public class EncapsulatedString
{
public String str;
public EncapsulatedString(String s)
{
str = s;
}
}
Create a wrapper that contains your object and change contents of the wrapper:
public class StringWrapper {
private String str;
public String getString() {
return str;
}
public String setString(String str){
this.str = str;
}
public String toString() {
return str;
}
}
public void one() {
StringWrapper s = new StringWrapper();
s.setString("one");
two(w);
// This will print "two"
System.out.println(s);
}
public void two( StringWrapper s ) {
s.setString("two");
}
One ugly solution that comes to my mind is to pass around a String array of length 1. It's not something I would encourage but if you feel that you want to do it...
1 public class One {
2
3 public static void main( String[] _ ) {
4 String[] s = {"one"};
5 two(s);
6 System.out.println(s[0]);
7 }
8
9 public static void two( String[] s ) {
10 s[0] = "two";
11 }
12 }
1-length array is a bit ugly, but perfectly working solution. No need to create surplus wrapper classes:
public void one() {
String[] s = new String[]{"one"};
two(s);
System.out.println(s[0]);
}
public void two(String[] s) {
s[0] = "two";
}
This pattern is especially useful when translating old (e.g. C) code where pass by reference has been extensively applied.
That said, returning a new, fresh value is always less confusing than mutating the "input" value.
Use StringBuffer, or StringBuilder, which are mutable.
Java is not a pass-by-value language. On the contrary - it is a pass-by-reference language. (passing-by-reference does not mean you can change the original "pointer" to point elsewhere like C++ allows).
The only things which are passed by value are primitives (int, long, char etc.)
Object references are always passed by reference - so if your Object is able to support change to its contents (e.g. via getter and setter methods) - it can be changed.
String specifically is immutable - meaning that its contents may never be changed. So for your specific question, if you want the String referred to by the local variable 's' to change you need to provide it with a reference to a new instance of a String object.
Example:
public void one()
{
String s = "one";
s = two(); // Here your local variable will point to a new instance of a String with the value "two"
System.out.println(s);
}
public String two()
{
return "two";
}
If you use objects other than String - you can define setter methods on them that will update their contents for you.

Passing a String by Reference in Java?

I am used to doing the following in C:
void main() {
String zText = "";
fillString(zText);
printf(zText);
}
void fillString(String zText) {
zText += "foo";
}
And the output is:
foo
However, in Java, this does not seem to work. I assume because the String object is copied instead of passed by referenced. I thought Strings were objects, which are always passed by reference.
What is going on here?
You have three options:
Use a StringBuilder:
StringBuilder zText = new StringBuilder ();
void fillString(StringBuilder zText) { zText.append ("foo"); }
Create a container class and pass an instance of the container to your method:
public class Container { public String data; }
void fillString(Container c) { c.data += "foo"; }
Create an array:
new String[] zText = new String[1];
zText[0] = "";
void fillString(String[] zText) { zText[0] += "foo"; }
From a performance point of view, the StringBuilder is usually the best option.
In Java nothing is passed by reference. Everything is passed by value. Object references are passed by value. Additionally Strings are immutable. So when you append to the passed String you just get a new String. You could use a return value, or pass a StringBuffer instead.
What is happening is that the reference is passed by value, i.e., a copy of the reference is passed. Nothing in java is passed by reference, and since a string is immutable, that assignment creates a new string object that the copy of the reference now points to. The original reference still points to the empty string.
This would be the same for any object, i.e., setting it to a new value in a method. The example below just makes what is going on more obvious, but concatenating a string is really the same thing.
void foo( object o )
{
o = new Object( ); // original reference still points to old value on the heap
}
java.lang.String is immutable.
I hate pasting URLs but https://docs.oracle.com/javase/10/docs/api/java/lang/String.html is essential for you to read and understand if you're in java-land.
All arguments in Java are passed by value. When you pass a String to a function, the value that's passed is a reference to a String object, but you can't modify that reference, and the underlying String object is immutable.
The assignment
zText += foo;
is equivalent to:
zText = new String(zText + "foo");
That is, it (locally) reassigns the parameter zText as a new reference, which points to a new memory location, in which is a new String that contains the original contents of zText with "foo" appended.
The original object is not modified, and the main() method's local variable zText still points to the original (empty) string.
class StringFiller {
static void fillString(String zText) {
zText += "foo";
System.out.println("Local value: " + zText);
}
public static void main(String[] args) {
String zText = "";
System.out.println("Original value: " + zText);
fillString(zText);
System.out.println("Final value: " + zText);
}
}
prints:
Original value:
Local value: foo
Final value:
If you want to modify the string, you can as noted use StringBuilder or else some container (an array or an AtomicReference or a custom container class) that gives you an additional level of pointer indirection. Alternatively, just return the new value and assign it:
class StringFiller2 {
static String fillString(String zText) {
zText += "foo";
System.out.println("Local value: " + zText);
return zText;
}
public static void main(String[] args) {
String zText = "";
System.out.println("Original value: " + zText);
zText = fillString(zText);
System.out.println("Final value: " + zText);
}
}
prints:
Original value:
Local value: foo
Final value: foo
This is probably the most Java-like solution in the general case -- see the Effective Java item "Favor immutability."
As noted, though, StringBuilder will often give you better performance -- if you have a lot of appending to do, particularly inside a loop, use StringBuilder.
But try to pass around immutable Strings rather than mutable StringBuilders if you can -- your code will be easier to read and more maintainable. Consider making your parameters final, and configuring your IDE to warn you when you reassign a method parameter to a new value.
objects are passed by reference, primitives are passed by value.
String is not a primitive, it is an object, and it is a special case of object.
This is for memory-saving purpose. In JVM, there is a string pool. For every string created, JVM will try to see if the same string exist in the string pool, and point to it if there were already one.
public class TestString
{
private static String a = "hello world";
private static String b = "hello world";
private static String c = "hello " + "world";
private static String d = new String("hello world");
private static Object o1 = new Object();
private static Object o2 = new Object();
public static void main(String[] args)
{
System.out.println("a==b:"+(a == b));
System.out.println("a==c:"+(a == c));
System.out.println("a==d:"+(a == d));
System.out.println("a.equals(d):"+(a.equals(d)));
System.out.println("o1==o2:"+(o1 == o2));
passString(a);
passString(d);
}
public static void passString(String s)
{
System.out.println("passString:"+(a == s));
}
}
/* OUTPUT */
a==b:true
a==c:true
a==d:false
a.equals(d):true
o1==o2:false
passString:true
passString:false
the == is checking for memory address (reference), and the .equals is checking for contents (value)
String is an immutable object in Java. You can use the StringBuilder class to do the job you're trying to accomplish, as follows:
public static void main(String[] args)
{
StringBuilder sb = new StringBuilder("hello, world!");
System.out.println(sb);
foo(sb);
System.out.println(sb);
}
public static void foo(StringBuilder str)
{
str.delete(0, str.length());
str.append("String has been modified");
}
Another option is to create a class with a String as a scope variable (highly discouraged) as follows:
class MyString
{
public String value;
}
public static void main(String[] args)
{
MyString ms = new MyString();
ms.value = "Hello, World!";
}
public static void foo(MyString str)
{
str.value = "String has been modified";
}
The answer is simple. In java strings are immutable. Hence its like using 'final' modifier (or 'const' in C/C++). So, once assigned, you cannot change it like the way you did.
You can change which value to which a string points, but you can NOT change the actual value to which this string is currently pointing.
Ie. String s1 = "hey". You can make s1 = "woah", and that's totally ok, but you can't actually change the underlying value of the string (in this case: "hey") to be something else once its assigned using plusEquals, etc. (ie. s1 += " whatup != "hey whatup").
To do that, use the StringBuilder or StringBuffer classes or other mutable containers, then just call .toString() to convert the object back to a string.
note: Strings are often used as hash keys hence that's part of the reason why they are immutable.
String is a special class in Java. It is Thread Safe which means "Once a String instance is created, the content of the String instance will never changed ".
Here is what is going on for
zText += "foo";
First, Java compiler will get the value of zText String instance, then create a new String instance whose value is zText appending "foo". So you know why the instance that zText point to does not changed. It is totally a new instance. In fact, even String "foo" is a new String instance. So, for this statement, Java will create two String instance, one is "foo", another is the value of zText append "foo".
The rule is simple: The value of String instance will never be changed.
For method fillString, you can use a StringBuffer as parameter, or you can change it like this:
String fillString(String zText) {
return zText += "foo";
}
Strings are immutable in Java.
This works use StringBuffer
public class test {
public static void main(String[] args) {
StringBuffer zText = new StringBuffer("");
fillString(zText);
System.out.println(zText.toString());
}
static void fillString(StringBuffer zText) {
zText .append("foo");
}
}
Even better use StringBuilder
public class test {
public static void main(String[] args) {
StringBuilder zText = new StringBuilder("");
fillString(zText);
System.out.println(zText.toString());
}
static void fillString(StringBuilder zText) {
zText .append("foo");
}
}
String is immutable in java. you cannot modify/change, an existing string literal/object.
String s="Hello";
s=s+"hi";
Here the previous reference s is replaced by the new refernce s pointing to value "HelloHi".
However, for bringing mutability we have StringBuilder and StringBuffer.
StringBuilder s=new StringBuilder();
s.append("Hi");
this appends the new value "Hi" to the same refernce s.
//
Aaron Digulla has the best answer so far. A variation of his second option is to use the wrapper or container class MutableObject of the commons lang library version 3+:
void fillString(MutableObject<String> c) { c.setValue(c.getValue() + "foo"); }
you save the declaration of the container class. The drawback is a dependency to the commons lang lib. But the lib has quite a lot of useful function and almost any larger project i have worked on used it.
For passing an object (including String) by reference in java, you might pass it as member of a surrounding adapter. A solution with a generic is here:
import java.io.Serializable;
public class ByRef<T extends Object> implements Serializable
{
private static final long serialVersionUID = 6310102145974374589L;
T v;
public ByRef(T v)
{
this.v = v;
}
public ByRef()
{
v = null;
}
public void set(T nv)
{
v = nv;
}
public T get()
{
return v;
}
// ------------------------------------------------------------------
static void fillString(ByRef<String> zText)
{
zText.set(zText.get() + "foo");
}
public static void main(String args[])
{
final ByRef<String> zText = new ByRef<String>(new String(""));
fillString(zText);
System.out.println(zText.get());
}
}
For someone who are more curious
class Testt {
static void Display(String s , String varname){
System.out.println(varname + " variable data = "+ s + " :: address hashmap = " + s.hashCode());
}
static void changeto(String s , String t){
System.out.println("entered function");
Display(s , "s");
s = t ;
Display(s,"s");
System.out.println("exiting function");
}
public static void main(String args[]){
String s = "hi" ;
Display(s,"s");
changeto(s,"bye");
Display(s,"s");
}
}
Now by running this above code you can see how address hashcodes change with String variable s .
a new object is allocated to variable s in function changeto when s is changed

Categories