pne: A typographical ligature of the lowercase letters "wtf" (wtf ligature)

OK, this is the third thing this day; I’ma start a new entry which I’ll update occasionally.

Now this one is not so much incorrect, but still, the irony just slays me:

int key []; // brackets after name (legal but less readable)
            // spaces between the name and [] legal, but bad

Spaces before the [] are bad? Like the spaces they use in String [] args in just about every main method in the book?

The mind, it reels.


OK, not a WTF as such, but still:

[…] Instance init blocks are often used as a place to put code that all the constructors in a class should share. That way, the code doesn't have to be duplicated across constructors.

I’d like to dispute the “often” in there, given that I had never heard of instance init blocks before (nor seen then used), ever. (Though the syntax and usage is reasonable based on what I did know about static init blocks.)


I’m also distinctly unimpressed that one of the questions in the self-test in Chapter 2 relies on overloading method resolution information that will be taught in Chapter 3.


More String nonsense

Creating String objects

Oh dear! More nonsense about how String objects work:

In Java, strings are objects. Just like other objects, you can create an instance of a String with the new keyword, as follows:

String s = new String();

This line of code creates a new object of class String, and assigns it to the reference variable s. So far, String objects seem just like other objects. Now, let's give the String a value:

s = "abcdef";

As you might expect, the String class has about a zillion constructors, so you can use a more efficient shortcut:

String s = new String("abcdef");

And just because you'll use strings all the time, you can even say this:

String s = "abcdef";

There are some subtle differences between these options that we'll discuss later, but what they have in common is that they all create a new String object, with a value of "abcdef", and assign it to a reference variable s.

Except that the first pair of statements created two String objects: one for the empty string (which got assigned to the s variable), and then another one containing "abcdef", which then also got assigned to s (leaving the object that s previously referred to, the empty string, not referred to any more (and presumably eligible for garbage collection).

One string object and two string objects seems like a difference to me.

Understanding Strings

…Oh dear, and a bit later, they say:

[…] If you really, really get the examples and diagrams, backward and forward, you should get 80 percent of the String questions on the exam correct.

I think I do; thanks! It just doesn’t seem to me as if the authors did….

Substring index values

[…] If the [substring() method] call has two arguments, the substring returned will end with the character located in the nth position of the original String where n is the second argument. Unfortunately, the ending argument is not zero-based, so if the second argument is 7, the last character in the returned String will be in the original String's 7 position, which is index 6 (ouch). […]

Ouch indeed. Wouldn’t explaining that the indexes run from beginIndex, inclusive, to endIndex, exclusive, have been easier than invoking one-based counting?

Or using wording such as “the substring returned will end with the character immediately before the index given by the second argument”.

Why StringBuilder is better than String, or, When objects get added to the String constant pool

Introduction

[…] if you choose to do a lot of manipulations with String objects, you will end up with a lot of abandoned String objects in the String pool. (Even in these days of gigabytes of RAM, it's not a good idea to waste precious memory on discarded String pool objects.) On the other hand, objects of type StringBuffer and StringBuilder can be modified over and over again without leaving behind a great effluence of discarded String objects.

Is this really the reason?

As I understand it, every string literal will be added to the String constant pool, but results of methods such as String.concat() will not.

So

String s = "Hello ";
s += "world, ";
s += "how are ";
s += "you?";

Would end up with four objects in the String constant pool (the four string literals), one String object on the heap (with value Hello world, how are you?) pointed to by s, and two String objects on the heap produced by the += operator (with values Hello world, and Hello world, how are ) which are not pointed to by anything and are eligible for garbage collection.

While if you did

StringBuilder s = new StringBuilder(26);
s.append("Hello ");
s.append("world, ");
s.append("how are ");
s.append("you?");

Would end up with… tada, four! objects in the String constant pool, as before! Since we still have four String literals in the source.

You’d avoid the two temporary String objects produced by the concatenation in the first example, but those are (if I understand correctly) on the heap and eligible for garbage collection, not “wast[ing] precious memory” as a case of “discarded String pool objects”. Sure, those are “discarded String objects”, but they’re not clogging up the scarce String pool resource and never getting freed. So you’re still polluting your scarce resource just as much as before, just using a bit less of a less-scarce one (the heap).

…and if you had used the new StringBuilder(); constructor instead, you’d have a discarded char[] lying around on the pool from when the StringBuilder had to resize from its default 16 to 34 characters upon appending the “how are ” bit. So on this particular example, you save one heap object with StringBuilder compared to String.

Using StringBuilder and StringBuffer

String x = "abc";
x = x.concat("def");
System.out.println("x = " + x);     // output is "x = abcdef"

We got a nice new String out of the deal, but the downside is that the old String "abc" has been lost in the String pool, thus wasting memory. If we were using a StringBuffer instead of a String, the code would look like this:

StringBuffer sb = new StringBuffer("abc");
sb.append("def");
System.out.println("sb = " + sb);    // output is "sb = abcdef"

…which would still lose “the old String "abc"” to the String pool, as I understand it, since it would be added to the String pool at the point where the compiler saw the String literal "abc" in the source code: it would create a String object in the constant pool (or find an existing String object with that value in the pool), and then pass that String object to the constructor of StringBuffer. You’re not doing the constant pool any favours here.


Lenient: I don’t think that means what you think it means.

The API for DateFormat.parse() explains that by default, the parse() method is lenient when parsing dates. Our experience is that parse() isn't very lenient about the formatting of Strings it will successfully parse into dates; take care when you use this method!

I wonder whether they’re using the same definition of “lenient” as the API; it doesn’t mean that it can take stuff such as “last Thursday” or “ye 13th of the monthe of Maye of the Year of Our Lord 1492”, but rather that it can take stuff such as “2001-2-31” and turn it into “2001-03-03”. As the API says, it does have to be parsable as a date; but you can omit leading zeroes or talk about the 31st of February.

pne: A typographical ligature of the lowercase letters "wtf" (wtf ligature)

Quoth the SCJP study guide:

Arrays are efficient, but most of the time you'll want to use one of the Collection types from java.util (including HashMap, ArrayList, TreeSet). Collection classes [… a]re really managed arrays, since they use arrays behind the scenes. […]

ORLY. Show me how a TreeSet uses arrays behind the scenes. Or a LinkedList, which—though they didn’t mention it explicitly—is also “one of the Collection types from java.util”.)

Feh.

If this goes on much further, I’ll have to create a separate entry just for their weirdness rather than posting as I go along.

pne: A picture of a plush toy, halfway between a duck and a platypus, with a green body and a yellow bill and feet. (Default)

So I’m preparing for the Sun Certified Java Programmer for Java 6 course (now Oracle Certified Professional or something like that, I think, but the book still calls it SCJP).

And I come across this lovely bit in chapter 3:

One exception to the way object references are assigned is String. In Java, String objects are given special treatment. For one thing, String objects are immutable; you can't change the value of a String object […]. But it sure looks as though you can. Examine the following code:

[…]
String x = "Java";  // Assign a value to x
[…]
x = x + " Bean";    // Now modify the object using
                    // the x reference

[…]

For any other object type, where two references refer to the same object, if either reference is used to modify the object, both references will see the change because there is still only a single object. But any time we make any changes at all to a String, the VM will update the reference variable to refer to a different object. […]

You need to understand what happens when you use a String reference variable to modify a string:

  • A new string is created (or a matching String is found in the String pool), leaving the original String object untouched.
  • The reference used to modify the String (or rather, make a new String by modifying a copy of the original) is then assigned the brand new String object.

So when you say

1. String s = "Fred";
2. String t = s;     // Now t and s refer to the same
                     // String object
3. t.toUpperCase();  // Invoke a Strong method that changes
                     // the String

you haven't changed the original String object created on line 1. When line 2 completes, both t and s reference the same String object. But when line 3 runs, rather than modifying the object referred to by t (which is the one and only String object up to this point), a brand new String object is created. And then abandoned. […]

(Emphasis in the original.)

Which contains a bunch of lies. (Not all of it, but too much of it.)

As best as I can see, String objects aren’t special in this particular respect; the same is true of other immutable classes.

It all boils down to the fact that you can’t modify String objects. If you want to change the value, you get a new String object, whether this is because you applied an operator (s + " Bean") or called a method on it (t.toUpperCase()). Assigning this new object to a variable, uh, assigns this new object to the variable. Same behaviour as when you assign any new object to a reference variable: other variables that reference the object that the variable used to point to continue to refer to the previous object.

It’s exactly the same with, say, java.math.BigDecimal, which is also not mutable and which returns new objects if you try to do arithmetic. For example, in BigDecimal first = new BigDecimal("17"); BigDecimal copy = first; BigDecimal second = new BigDecimal("21"); first = first.add(second);, the “add” method will return a new BigDecimal object. If you turn around and assign it straight back to the variable “first”, then that doesn’t change the BigDecimal object that had the value 17; that one is still around and still pointed to by the variable “copy”; it’s just not pointed to by the variable “first” any more.

So s = s + " Bean"; is not any more special than s = "C#";; in both cases, we point the variable to a new String object. There’s no “mak[ing] any changes […] to a String” or “changes the String” of any kind going on anywhere, nor any “special treatment” of String objects that I can see.

Feh.

Profile

pne: A picture of a plush toy, halfway between a duck and a platypus, with a green body and a yellow bill and feet. (Default)
Philip Newton

June 2015

S M T W T F S
 12 3456
78910111213
14151617181920
2122232425 2627
282930    

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Tuesday, 22 August 2017 10:56
Powered by Dreamwidth Studios