tag:blogger.com,1999:blog-107606732024-03-19T02:16:00.650-07:00smallwigPersonal ramblings of Kevin Bourrillion, senior software engineer at Google, Inc.
<p>No, my opinions as expressed in this blog are not those of my employer. They're mine alone. That's why they're called "my opinions." Helloooo.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.comBlogger40125tag:blogger.com,1999:blog-10760673.post-24722269400314516042011-10-13T22:22:00.002-07:002011-10-13T22:25:42.703-07:00Oh dear. I just discovered that some places still link my name to this site. Eep! A better link would probably be my <a href="https://plus.google.com/113026104107031516488/posts">Google Profile</a>, now.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com109tag:blogger.com,1999:blog-10760673.post-6654866243208752142010-06-14T10:38:00.000-07:002010-06-14T10:39:31.525-07:00Guava release 05!<span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: 11px; border-collapse: collapse; "><div><b><span style="font-size: large; ">Guava release 05!</span></b></div><div><br /></div>Hello guavateers,<div><br /></div><div>I'm happy to (finally) inform you that <a href="http://guava-libraries.googlecode.com/files/guava-r05.zip" target="_blank" style="color: rgb(28, 81, 168); ">Guava release 05</a> was quietly posted two weeks ago! It is also in the central maven repository as <a href="http://repo2.maven.org/maven2/com/google/guava/guava/r05/" target="_blank" style="color: rgb(28, 81, 168); ">com.google.guava:guava:r05</a> (as will all future releases, so you may stop asking :-)).</div><div> <br /></div><div>Here is a report of the <a href="http://guava-libraries.googlecode.com/svn/tags/release05/javadoc/jdiff/changes.html" target="_blank" style="color: rgb(28, 81, 168); ">changes between r04 and r05</a>. For that matter, here are the <a href="http://guava-libraries.googlecode.com/svn/tags/release04/javadoc/jdiff/changes.html" target="_blank" style="color: rgb(28, 81, 168); ">changes from r03 to r04</a> as well. There have been a few very nice new additions, as I hope you'll agree -- including the humble beginnings of a brand new package, <a href="http://guava-libraries.googlecode.com/svn/tags/release05/javadoc/com/google/common/net/package-summary.html" target="_blank" style="color: rgb(28, 81, 168); ">com.google.common.net</a>.</div><div><br /></div><div>Remember that most newly-added classes and methods are marked <b>@Beta</b>, and so are still subject to change at any time. Note: this is particularly true of the cool new <a href="http://guava-libraries.googlecode.com/svn/tags/release05/javadoc/com/google/common/net/InternetDomainName.html" target="_blank" style="color: rgb(28, 81, 168); ">InternetDomainName</a> class, several methods of which I already need to rename soon (sorry).</div><div><br /></div><div><b><span style="font-size: large; ">About the "Google Collections Library":</span></b></div><div><br /></div><div>Everyone! It's time to stop using the library called the "Google Collections Library"! Guava represents a<b> fully-compatible proper superset</b> of that library. It also contains six months worth of<b>important bug fixes</b> and improvements to performance and documentation.</div><div><br /></div><div>Continuing to use the Google Collections may lead to trouble when an application ends up with both that and Guava on the classpath at the same time. If this happens, and Guava comes <i>later</i> in the classpath, <b>unpredictable breakages</b> could result! (And if Guava comes <i>earlier</i>, then the google-collect JAR will never even be seen; either way, the situation is senseless.)</div><div><br />Tools like Maven seek to manage your dependencies in an intelligent way, but cannot tell that Guava represents a newer version of Google Collections, so as long as the latter is still in use, it won't know the right thing to do with it.</div><div><br /></div><div>Yes, the Guava JAR file is about 60% larger than the Google Collections one, but if this is an issue for you, we strongly recommend you address this using a JAR shrinking tool such as the much-loved <a href="http://proguard.sourceforge.net/" target="_blank" style="color: rgb(28, 81, 168); ">ProGuard</a>, and please share your experiences in doing so with the rest of us on this list.</div><div><br /></div><div><b><span style="font-size: large; ">Publicity?</span></b></div><div><br /></div><div>With this release, I now see Guava as truly ready to be evangelized to the corners of the globe. Would you be able to help us spread the word? Blogs, comments, twitter, podcasts, company discussion forums, skywriting, whatever you please. It's especially important to me that we convey the message that Guava is the new Google Collections, and no one should use google-collect-1.0.jar anymore.</div><div><br /></div><div><span style="font-size: large; "><b>Any questions?</b></span></div><div><br /></div><div>Thanks everyone!</div></span>Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com72tag:blogger.com,1999:blog-10760673.post-75195531288681588472010-03-01T14:44:00.000-08:002010-03-01T15:15:43.091-08:00The little optimization that couldn't<div>Let's say you represent two groups of people. If I collect one penny from each member of Group A, then, from the unbounded kindness of my heart, give one dollar to each member of Group B, has the total wealth of the groups combined become greater or less?</div><div><br /></div><div>If you answered "greater", this article's for you! You see, there's a question you forgot to ask -- and it's a question that we as programmers forget to ask constantly.</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;">A nicely optimized method?</span></div><div><br /></div><div>In our internal core Java libraries at Google, we have a method called StringUtil.repeat(). It returns a string consisting of n copies of a base string -- so StringUtil.repeat("hey", 3) produces "heyheyhey". When I first came across it, and cleaned it up a bit, its implementation looked a little bit like this:</div><div><br /></div><div></div><blockquote><div><span class="Apple-style-span" style="font-family:'courier new';">public static String repeat(String base, int count) {</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> if (base.equals("") || count == 0) {</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> return "";</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> }</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> if (count == 1) {</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> return base;</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> }</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> StringBuilder sb = new StringBuilder(base.length() * count);</span></div><div> for (int i = 0; i < count; i++) {</div><div><span class="Apple-style-span" style="font-family:'courier new';"> sb.append(base);</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> }</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> return sb.toString();</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">}</span></div><div></div></blockquote><div><br /></div><div>What's going on here? Well, there are four basic cases.</div><div><br /></div><div><b>Case one:</b> base is the empty string, so the result should always be the empty string. We don't want to loop and all that, so this optimization returns an empty string straight away.</div><div><br /></div><div><b>Case two:</b> count is zero. Here again, why do any actual work? We should return the empty string here and now.</div><div><br /></div><div><b>Case three:</b> count is one. We can avoid instantiating a new string by returning the original string directly!</div><div><br /></div><div><b>Case four:</b> aww nuts. In this case, we really do have to loop and create the new string. Well, at least we optimized out as much ass we could first!</div><div><br /></div><div>In each case, we're very carefully doing the bare minimum amount of work we can! With me so far? Sounds good?</div><div><br /></div><div>When I found this, I proceeded to make the method run even faster. Any guesses how I did it? </div><div><br /></div><div>That's right, I simply removed all of these so-called optimizations.</div><div><br /></div><div>Remember that to optimize a special case, you must <i>check</i> for that special case... in every case! That small extra cost goes to every single user of the method. And what of the benefits? Hah! Notice that the "optimized" special cases are the cases that are the fastest to compute anyway!</div><div><br /></div><div>What's more, surprisingly enough, it doesn't really happen that often that users call a repeat() method passing zero or one as the count. Why would they? Commonly, that is. So we're "optimizing" a case that hardly even exists, at the expense of all the cases that do exist. The special-case checks were a net loss, and better off removed.</div><div><br /></div><div>It's not like my removing them radically improved the performance of anyone's application. However, the experience is useful as a lesson. You'll encounter this same situation many times in many guises, and it will often be tempting to think about the benefits to the few rather than the overall aggregate cost to society as a whole (hmm... remind you of any politicians?) </div><div><br /></div><div>If the Group A of my opening scenario has thousands of times more members than Group B -- not to mention that dollar really turns out to be a dime -- it's a bad deal. Just say no!</div>Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com48tag:blogger.com,1999:blog-10760673.post-44960563534772822272009-04-06T15:37:00.000-07:002009-04-06T15:37:31.650-07:00Anyone still out there?Wow, I can't believe it's already been almost a year since I posted anything meaningful on this blog. Blogging is a total ON/OFF switch with me.<br /><br />However, now I must post, in order to tell you that you should (a) listen to me and Jesse on <a href="http://javaposse.com/index.php?post_id=451742">Java Posse</a> (actually, we were on the previous episode also) and (b) download the <a href="http://google-collections.googlecode.com/files/google-collect-1.0-rc1.zip">first release candidate of Google Collections Library 1.0</a>!<br /><br />Well, that's my news. How are you?Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com21tag:blogger.com,1999:blog-10760673.post-83269861308167867442008-09-23T15:32:00.000-07:002008-09-23T15:37:05.341-07:00So good I had to come out of blogging hiatus just to share it with you:<br /><blockquote>"Governor Palin, are you ready at this moment to perform surgery on this child's brain?"<br /><br />"Of course, Charlie. I have several boys of my own, and I'm an avid hunter."<br /><br />"But governor, this is neurosurgery, and you have no training as a surgeon of any kind."<br /><br />"That's just the point, Charlie. The American people want change in how we make medical decisions in this country. And when faced with a challenge, you cannot blink."<br /><br />The prospects of a Palin administration are far more frightening, in fact, than those of a Palin Institute for Pediatric Neurosurgery. Ask yourself: how has "elitism" become a bad word in American politics? There is simply no other walk of life in which extraordinary talent and rigorous training are denigrated. We want elite pilots to fly our planes, elite troops to undertake our most critical missions, elite athletes to represent us in competition and elite scientists to devote the most productive years of their lives to curing our diseases. And yet, when it comes time to vest people with even greater responsibilities, we consider it a virtue to shun any and all standards of excellence. When it comes to choosing the people whose thoughts and actions will decide the fates of millions, then we suddenly want someone just like us, someone fit to have a beer with, someone down-to-earth—in fact, almost anyone, provided that he or she doesn't seem too intelligent or well educated.<br /></blockquote>Incredibly well said by Sam Harris. <a href="http://www.newsweek.com/id/160080">Link</a>Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com10tag:blogger.com,1999:blog-10760673.post-54733025950694489702008-08-12T15:55:00.000-07:002008-08-12T16:00:00.251-07:00Google Collections presentationIf you'd like to know more about the Google Collections Library, here's a video you can watch:<br /><br /><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/ZeO_J2OcHYM&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/ZeO_J2OcHYM&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object><br /><br />It continues <a href="http://www.youtube.com/watch?v=9ni_KEkHfto">here</a>. Or if you're in a rush you can just skim the <a href="http://google-collections.googlecode.com/files/google-collections-svgtug-2008-08-06.pdf">slides</a>, not that I recommend it. :-)<br /><br />Hope you find it informative!Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com34tag:blogger.com,1999:blog-10760673.post-57239396709609536392008-07-09T17:25:00.001-07:002008-07-09T17:26:37.239-07:00I'm curious: what do you use to parse command-line options in your Java programs?<br /><br />You know, -r, -w, -rwl, --use-flibbert, --foobar=12 and all that kinda stuff.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com16tag:blogger.com,1999:blog-10760673.post-7396042338585925512008-07-02T10:28:00.000-07:002008-07-02T10:34:54.790-07:00small favorHey, everyone? Like, the next time you're making some clever analogy about something you don't like, involving the concept of "riding the short bus?" You know what I mean -- like "maan, with all these other cool languages nowadays, Java's really, heheh, riding the short bus!" (pat self on back)<br /><br />... Just kinda keep in mind that some of us have a son or daughter who's the love of our life who actually literally does ride the short bus. And your joke is just kinda less amusing to us. hokay? kthx, that's all.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com12tag:blogger.com,1999:blog-10760673.post-83238105283454136342008-06-16T10:44:00.000-07:002008-06-16T11:02:50.485-07:00Common Java unchecked exception typesI've noticed a lot of confusion about what type of unchecked exception is the right one to throw under various circumstances. Here's a very simple explanation of the most common types.<br /><br /><b>NullPointerException</b> - multiple schools of thought on this one. Of course, it's thrown automatically by the runtime when you try to dereference null. Many say that you should never rely on this behavior, and should always check for null explicitly. Many also believe that when you find a null reference, you should throw IllegalArgumentException instead of NPE. This way, a thrown NPE always indicates some programming error in the implementation of the method, not a failure of the caller to pass valid parameters. I'm not taking a stand on this issue right now.<br /><br /><b>IllegalArgumentException</b> - throwing this exception implies that there exists at least one other value for this parameter that would have caused the check in question to pass. If the caller can't remedy this exception by substituting another value for the argument in question, it's the wrong exception to throw. Note that in some of these cases IndexOutOfBoundsException is more appropriate (and strangely, IOOBE doesn't extend IAE).<br /><br /><b>IllegalStateException</b> - this exception implies that there are no argument values that could have caused the check to succeed, yet, there does exist at least one alternate state that the instance in question could have been in, which would have passed the check. Note that this type almost never makes sense for a static method, unless you rely heavily on static state (shame on you). Note also that this exception is appropriate whether or not it is possible to actually mutate this aspect of the instance's state, or it's already too late.<br /><br /><b>UnsupportedOperationException</b> - this means that the method invoked will always fail for an instance of this class (concrete type), regardless of how the instance was constructed.<br /><br /><b>AssertionError</b> - this is the right exception to use whenever a statement should by rights be impossible to reach.<br /><br />I hope this helps. Any points you want to argue?Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com20tag:blogger.com,1999:blog-10760673.post-69571231235041770782008-04-29T20:54:00.000-07:002008-04-29T21:05:30.600-07:00JavaOne approachethJust got my sessions all scheduled. As usual, I chose them more for the speakers than for the topics; there are certain individuals who I just know can speak well and tend to talk about topics I like -- people like Brian Goetz, Bill Pugh, Cliff Click, Joshua Bloch, etc. Whatever they talk about, I go.<br /><br />If you're attending this year, and you might like to meet me and chat about Java, collections, Guice, working at Google, the smallwig or whatever, well gosh, I'd like that too. What you can do is stop by the Google booth in the pavilion at one of these times:<ul><br /><li>Tuesday May 6, 2:00-3:00 pm<br /><li>Wednesday May 7, 12:30-1:30 pm<br /><li>Thursday May 8, 12:30-1:30 pm<br /></ul>And then look for the guy wearing a Google t-shirt who looks like <a href="http://video.google.com/videoplay?docid=121403207358911729">this</a> but needs a haircut. Say hello and we can talk about whatever. That would be cool.<br /><br />Also, if you're a Guice user, please see if you can come to <b>BOF-6400, The Future Of Guice</b>, which is on Thursday at 7:30 pm. <a href="http://www.crazybob.org">Bob</a>, <a href="http://www.publicobject.com">Jesse</a> and I will all be there for an informal fireside chat about forthcoming Guice goodness.<br /><br />Hope to see you!<br /><br />And for those not coming to JavaOne, what conferences will you be attending over the next year, if any?Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com4tag:blogger.com,1999:blog-10760673.post-73831532703612636812008-04-29T11:12:00.000-07:002008-04-29T11:14:12.045-07:00I'm a twitFor those who care about such things, I'm on <a href="http://twitter.com/kevinb9n">twitter</a> now.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com3tag:blogger.com,1999:blog-10760673.post-57292776499385013072008-04-25T10:26:00.000-07:002008-04-25T10:29:08.921-07:00Interesting Stuff I ReadI've added a link to <a href="http://www.google.com/reader/shared/14833113633033104455">my Google Reader shared items</a> in my sidebar. You can view that, or subscribe to its feed, or whatever! (You don't have to be using Google Reader... though you should). :-)Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com3tag:blogger.com,1999:blog-10760673.post-80267862568688392282008-04-24T13:29:00.000-07:002008-04-24T13:30:20.302-07:00I get to break awesome newsI asked Josh if I could have the pleasure of breaking this news on my li'l blog here, and unbelievably, he actually said "sure."<br /><br />Lucky me! Here's the news:<br /><br /><i>Effective Java, Second Edition</i> by Joshua Bloch <b>has gone to press</b> and copies will be available at JavaOne in two weeks.<br /><br />Hooray! We've been waiting for this for a long time.<br /><br />Having read it (again, lucky), I'll quickly tell you my opinion (personal opinion only, not an endorsement by my employer, and feel free to disregard it as biased if you like).<br /><br />You probably all know how valuable the first edition is already. The new edition really takes it a step further. It's vastly improved and has entire new sections on generics, enums, annotations, and other recent Java developments. The concurrency chapter was completely redone to reflect the "java.util.concurrent" new world order. There's a wealth of new information about serialization pitfalls and patterns, and the list goes on.<br /><br />It is not just the <i>Effective Java</i> you know with a few extra chapters tacked on! Josh has painstakingly revisited every single line of every single page. I believe it shows.<br /><br />This book will certainly replace its predecessor as the bible of our craft. Many of the code reviews I do for Java library code at Google basically end up with me spouting chapter and verse from EJ, and I can't wait for everyone to get the new edition so I can start doing the same with it!<br /><br />(Not linking to amazon because I'm peeved at them; they let you click "see inside the book" but then they just show you the insides of the first edition, leading you to think that nothing has changed.)Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com26tag:blogger.com,1999:blog-10760673.post-18099885620734811942008-04-24T12:15:00.000-07:002008-04-24T12:29:45.936-07:00Pure functionsTo its detriment and yours, the Java language makes no distinction between a <span style="font-style: italic;">pure function</span>, and any plain old subroutine. Even in the core libraries, the two are freely intermingled, with no obvious distinguishing characteristic. Yet we can all benefit from striving to make this distinction clear in our own code.<br /><br />By "pure function" I mean a function in the mathematical sense: it performs a calculation with no observable side-effects, and its result depends only on its arguments. Invoke it again on the same instance (or Class if static), and with the same arguments in the same states, and you must <span style="font-style: italic;">always</span> get the same answer.<br /><br /><b>What are some advantages of pure functions?</b><br /><ul><br /><li>They're testable<br /><li>They're thread-safe (though not necessarily "thread-correct", more on this later)<br /><li>They're deterministic<br /><li>They never need to be mocked out*<br /><li>They're easier to understand and reason about<br /><li>They're "referentially transparent," so they can be "memoized" (more on this later)<br /></ul><br />They're the easy kind of functions to work with, just like immutables are the easy variety of data objects.<br /><br />(*About this particular claim. Have you ever felt compelled to test how your class behaves if the implementation of integer addition were to change? I doubt it, unless you're just plain batshit crazy, or a mathematician (but I repeat myself). In rare cases, if a pure function is very expensive, you may want to mock it anyway just to make your test runs faster. But you didn't "need" to do it.)<br /><br /><b>When is a function pure?</b><br /><br />All its dependencies must be pure functions themselves (or constants, which are basically just pure functions that have no arguments). Impurity, just like it sounds, is a contaminant. If your method calls eight other methods, and just one of those calls a method which <span style="font-style: italic;">sometimes</span> calls a method which uses <span style="font-family: courier new;">System.currentTimeMillis()</span>, kaboom: your function is not pure.<br /><br />So a method which invokes <span style="font-family:courier new;">new Random(5)</span> may still be pure (as guaranteed by that class's specification), while one that invokes <span style="font-family:courier new;">new Random()</span> certainly is not. <s><span style="font-family:courier new;">Collections.shuffle()</span>, the two-argument form, is pure, while <span style="font-family:courier new;">Collections.shuffle()</span> the one-argument form is not.</s> <i>(wait, duh, neither is pure, because they mutate the passed-in list! but maybe you see the point anyway?)</i> Now you see the "intermingling" I was bemoaning before!<br /><br /><b>What are the most common sources of impurity in my code?</b><br /><br />Some I can think of:<br /><ul><li>mutable state<li>the system clock<li>I/O</ul><br />I'm sure there are more. Help me out here: what others can you think of?<br /><br /><b>Are impure functions evil?</b><br /><br />No, of course not. If they were, I would never be able to write any, as it would be against company policy. They're simply <span style="font-style: italic;">very different</span> from their pure cousins, and more challenging to work with and to test. Keeping your functions pure, like keeping your value objects immutable, just gives you less to worry about. (Remember that hit song "Mo' Mutatin', Mo' Problems?" Toootally analogous to that. Listen to Biggie, he knew.)<br /><br /><b>How to deal with impurity?</b><br /><br />I've told you that the system clock is a contaminant, that makes everything it touches impure. But, of course, some of your business logic probably needs to know the current time. Are you just hopelessly contaminated as well?<br /><br />No! You have at your disposal a chlorine tablet called <span style="font-style: italic;">dependency injection</span>! (You just knew it would come to that, didn't you?)<br /><br />Before:<br /><br /><pre> public class SignUtils {<br /> public static String getCurrentMessage() {<br /> Instant now = <b>new Instant();</b> // automatically set to now<br /> return someCalculation(now) ? "OPEN" : "CLOSED";<br /> }<br /> }</pre><br />After (simplified):<br /><br /><pre> public class SignController {<br /> <b>@Inject Clock clock;</b><br /> public static String getCurrentMessage() {<br /> Instant now = <b>clock.now()</b>;<br /> return someCalculation(now) ? "OPEN" : "CLOSED";<br /> }<br /> }</pre><br />The result is a function which can be either pure or impure depending on what dependencies are provided for it. In "real life", you need it to be impure, and return a different result at 9:01 than it did at 8:59. But this nondeterminism has now been walled off behind an interface. Because the result of <span style="font-family:courier new;">getCurrentMessage()</span> itself now depends only on the states of its arguments (none) and the state of its instance, it will always be just as pure as its provided clock instance is. Now the code is testable, because we properly isolated the impurity.<br /><br />In summary:<br /><ul><li>Pay attention to the difference between your pure and impure functions.</li><li>Use dependency injection to limit the damage radius of impure functions.</li><li>If you're designing the Next Great Language, ferchrissakes handle these two things differently. Don't make the system time available via a simple static method call.<br /></li></ul><br />Thanks for reading. Let me know if this kind of post is helpful to you!Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com12tag:blogger.com,1999:blog-10760673.post-74154250871980262652008-04-22T18:06:00.000-07:002008-04-24T09:07:14.372-07:00fun with IdentityHashMapWhat does this program print? (Eliding the generics so you can read it.)<br /><br /><pre>public static void main(String[] args) {<br /> Map m = new IdentityHashMap();<br /> m.put("a", 1);<br /> m.put("a", 2);<br /> m.put("a", 3);<br /> System.out.println(new HashSet(m.entrySet()).size());<br />}</pre><br /><br />When you've got the answer, scroll down...<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />The answer is 1. Even though this is an identity-based HashMap, String literals are interned, so after the first entry is created, it is overwritten two times leaving a map of size one. This single entry will then be placed into the HashSet, so the HashSet has size one.<br /><br />If you got it right, congrats. Now let's make a small change.<br /><br /><pre>public static void main(String[] args) {<br /> Map m = new IdentityHashMap();<br /> m.put("a", 1);<br /> m.put("b", 2);<br /> m.put("c", 3);<br /> System.out.println(new HashSet(m.entrySet()).size());<br />}</pre><br /><br />Now what does it print?<br /><br />Once you've decided on your answer, compile and run the code (sorry about the warnings). Were you right?<br /><br /><b>Update:</b> Ok, this isn't doing the same thing for y'all that it was doing for me. And now it's not doing it for me either. :) Ok look. Try this: remove the call to .size(). Just print out the entry set itself. Guess what it's going to be first. Then see. It'll be worth it, really!Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com13tag:blogger.com,1999:blog-10760673.post-62943622843442954452008-04-21T14:53:00.000-07:002008-04-21T14:58:29.271-07:00" "Who among my readers believes that he/she has a firm grasp on the meaning of the term "whitespace" as it applies to modern Java development?<br /><br />Anyone?<br /><br />Whitespace! How much simpler could anything be than that?<br /><br />Yeah. Well guess what. I've found, so far, six conflicting definitions worth knowing about. They are <a href="http://spreadsheets.google.com/pub?key=pd8dAQyHbdewRsnE5x5GzKQ">summarized in this table</a> for your viewing enjoyment. I daresay you will be surprised at how bad the situation is.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com2tag:blogger.com,1999:blog-10760673.post-35852559520428657742008-04-16T12:33:00.000-07:002008-04-17T09:57:01.016-07:00The real difference between List<Object> and List, illuminated at lastSuppose you're a store clerk, and a customer asks you, "what kinds of credit cards do you accept?"<br /><br />The difference between <span style="font-family:courier new;">List<Object><object><object><object></object></object></object></span> and <span style="font-family:courier new;">List</span> is basically the difference between answering this question "we accept all kinds," and answering it, "duuuuhhhhhhh?"Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com13tag:blogger.com,1999:blog-10760673.post-1782314191571387592008-04-16T11:38:00.000-07:002008-04-16T12:28:00.565-07:00The smallwig theory of optimizationThere are three kinds of optimization.<br /><ol><li> Optimization by using a more sensible overall approach.</li><li>Optimization by making the code less weird.</li><li>Optimization by making the code more weird.</li></ol>You've probably heard, and maybe even spouted yourself, the phrase "premature optimization is the root of all evil." It's exclusively "Type 3 optimization" that this aphorism applies to. Types 1 and 2 are quite fine to engage in pre-emptively.<br /><br />To make a type 3 optimization, your burdens are six:<br /><ol><li>Thou shalt have excellent, comprehensive unit tests.<br /></li><li>Thou shalt have a reliable benchmark, based on representative inputs.</li><li>Thou shalt demonstrate that your change improves the benchmark.</li><li>Thou shalt successfully argue that this improvement really matters.</li><li>Thou shalt comment the code.</li><li>In nontrivial cases, thou shalt also preserve the clear-but-slow implementation, to use in parity tests with your optimized implementation.<br /></li></ol>In all things, remember these truths:<br /><ol><li>Your brain is a terrible profiler.</li><li>Hotspot will outsmart you.</li><li>It just doesn't matter, until it matters.</li></ol>If you believe this post, please spread the word!Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com11tag:blogger.com,1999:blog-10760673.post-87035902622152849452008-01-25T13:14:00.000-08:002008-01-25T13:19:38.472-08:00Now with "customizable sodomy!"Holy shit, I want the version of Mass Effect that <a href="http://news.filefront.com/ignorance-is-astounding-conservative-blogger-claims-mass-effect-offers-%e2%80%9ccustomizable-sodomy%e2%80%9d/">this guy</a> played!<br /><br />Mine is apparently defective. A damn good game though... but I think the sex-with-blue-chicks was about as hot as Kirk's typical planetary exploits back in the 60s.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com9tag:blogger.com,1999:blog-10760673.post-85690240714677159972007-12-06T13:38:00.000-08:002007-12-06T13:39:25.706-08:00<a href="http://youtube.com/watch?v=Sr2JneittqQ">Can you watch this without smiling?</a><br /><br />If so... I don't know. You might be a replicant or something.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com78tag:blogger.com,1999:blog-10760673.post-73661682404668436792007-12-06T12:06:00.000-08:002007-12-06T12:45:12.325-08:00Why does Set.contains() take an Object, not an E?Virtually everyone learning Java generics is initially puzzled by this. Why should code like the following compile?<br /><pre><br /> Set<Long> set = new HashSet<Long>();<br /> set.add(10L);<br /> if (set.contains(10)) {<br /> // we won't get here!<br /> }<br /></pre><br />We're asking if the set contains the <i>Integer</i> ten; it's an "obvious" bug, but the compiler won't catch it because <tt>Set.contains()</tt> accepts <tt>Object</tt>. Isn't this stupid and evil?<br /><br />A popular myth is that it is stupid and evil, but it was necessary because of backward compatibility. But the compatibility argument is irrelevant; the API is correct whether you consider compatibility or not. Here's the real reason why.<br /><br />Let's say you have a method that wants to read from a Set of Foos:<br /><pre><br /> public void doSomeReading(Set<Foo> foos) { ... }<br /></pre><br />The problem with this signature is it won't allow a <tt>Set<SubFoo></tt> to be passed in (where <tt>SubFoo</tt> is, of course, a subtype of <tt>Foo</tt>).<br /><br />To preserve the <a href="http://en.wikipedia.org/wiki/Substitutability">substitutability principle</a>, any method that wants to read from a set of Foos should be equally able to read from a set of SubFoos, so let's tweak our signature:<br /><pre><br /> public void doSomeReading(Set<? extends Foo> foos) { ... }<br /></pre><br />Perfect!<br /><br />But here's the catch: if <tt>Set.contains()</tt> accepted type <tt>E</tt> instead of type <tt>Object</tt>, it would now be rendered completely unusable to you inside this method body!<br /><br />That signature tells the compiler, "don't let anyone ask about containment of an object unless you are damn sure that it's of the exact right type." But the compiler doesn't know the type -- it could be a <tt>Foo</tt>, or <tt>SubFoo</tt>, or <tt>SubSubFoo</tt>, or who knows what? Thus the compiler would have to forbid <i>everything</i> -- the only safe parameter to a method like this is <tt>null</tt>.<br /><br />This is the behavior you want for a method like <tt>Set.add()</tt> -- if you can't make damn sure of the type, don't allow it. And that's why <tt>add()</tt> accepts only type <tt>E</tt> while <tt>contains()</tt> accepts anything.<br /><br />So the distinction I'm making is between read methods and write methods, right? No, not exactly -- notice that <tt>Set.remove()</tt> also accepts <tt>Object</tt>, and it's a write method. The real difference is that <tt>add()</tt> can cause "damage" to the collection when called with the wrong type, and <tt>contains()</tt> and <tt>remove()</tt> cannot.<br /><br />Uniformly, methods of the Java Collections Framework (and the Google Collections Library too) never restrict the types of their parameters except when it's necessary to prevent the collection from getting broken.<br /><br />So what to do about this vexing source of bugs, as illustrated at top? Well, when I typed that code into IntelliJ, it flagged a warning for me right away. This let me know to either fix the problem or add an annotation/comment to suppress it. Problem solved.<br /><br /><b>Static analysis plays an extremely important role in the construction of bug-free software.</b> And the very best kind of static analysis is the kind that pops up in your face the second you write something questionable.<br /><br />The moral of the story: if you're not coding in a good, modern IDE, you're coding with one hand tied behind your back!Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com809tag:blogger.com,1999:blog-10760673.post-26653604503044229952007-11-15T14:05:00.001-08:002007-11-15T14:10:12.032-08:00Occam's CoderWhen deciding between two or more choices for a style rule in your team's programming style guide, and all of these lead to code that is equally maintainable, prefer the rule you can explain in the fewest words.<br /><br />"Readability" is also everyone's goal, but fails as a criterion because it is far too subjective.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com13tag:blogger.com,1999:blog-10760673.post-31734158434743458492007-11-09T03:53:00.000-08:002007-11-09T04:01:12.591-08:00What Google Java engineers do while... waiting... for IntelliJ to unhose itself...This discussion happened on our internal Java mailing list.<br /><br />Dan: "What libraries do people use for generating PDFs from java?"<br /><br />Tim: "I used <a href="http://www.lowagie.com/iText/">iText</a>. It works pretty well."<br />Fernando: "+1 for iText."<br />Steve: "Ditto"<br />Joseph: "we are using itext..."<br />Mike: "Calendar uses iText..."<br />Isaac: "+1 for iText on (Google Spreadsheets)"<br /><br />Me: "Did six Googlers just AGREE on something in a company-wide mailing list thread?? Did that really just happen?? My God, there really is a first time for everything."<br /><br />Mike: "I disagree. This assumes that time runs in a single direction. If it doesn't, then if an event occurs more than once then the first time could be called the last time and vice versa so neither can be reliably called a first time."<br /><br />Me: "I've now gained a new appreciation for the complexity of the problems you folks on the Calendar team have to contend with. Clearly we're moving beyond i18n to i19n: interuniversalization!"<br /><br />Mike: "Yep. We have an implemention of scheduling in multiple time dimensions ready to go and Jeff allocated a pocket universe for testing but production doesn't want to set up a datacenter there."<br /><br />Kathrin: "Can't you test in a parallel universe where production has agreed to set up your datacenter?"<br /><br />Well, I laughed my ass off.Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com20tag:blogger.com,1999:blog-10760673.post-43741179985329142602007-11-06T10:58:00.000-08:002007-11-06T11:11:21.900-08:00Minor API fixes for JDK 7Josh, Doug and I are proposing a handful of <a href="http://docs.google.com/Doc?id=dg6xkh5g_6c3vm4r">minor API additions</a> to the Java Class Libraries (lang, util, math and reflect) for JDK 7.<br /><br />The very quick overview of our recommendations:<br /><ol><li>Static compare() methods for all non-void wrapper classes, not just Double and Float.</li><li>Static hashCode() methods on all non-void wrapper classes.</li><li>Integer.mod() and Long.mod()</li><li>RoundingMode.round(double)</li><li>Arrays.concat()</li><li>EnumSet.complementOf(Collection)</li><li>All JDK maps should implement putIfAbsent(), etc.<br /></li><li>Proxy.newProxyInstance(type, handler)</li></ol>We're pretty confident that these changes will make it into JDK 7, barring any particular controversy that could develop.<br /><br />Please have a read over the document. What do you think about our proposals? What do you think we've missed?Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com19tag:blogger.com,1999:blog-10760673.post-69871183091373567322007-11-03T12:14:00.000-07:002007-11-03T12:18:21.765-07:00pseudohumor<pre><br />if (isBloggingInPseudocode()<br /> && intendedEffect() == Effect.HUMOR) {<br /> try {<br /> beFunny();<br /> // this line unreachable<br /> } catch (NotFunnyException e) {<br /> feign(Reaction.SURPRISE);<br /> }<br />}<br /></pre>Kevin Bourrillionhttp://www.blogger.com/profile/06900822537110311228noreply@blogger.com6