How to get a list item in Java - the wrong way



  • I finally decided to share this WTF written by my co-worker who didn't work for us very long. The reason might be that Java was not really his language and he never bothered to check out the (java)docs either...

    But when presented a challenge - how to get the first integer from a List of integers, did he check the Javadoc and find the .get(index) -method? Of course not, that would have been... uninventive!

    Here's his solution:

    List<Integer> myList = ...;
    int firstNumber = Integer.parseInt(myList.toString().substring(myList.toString().indexOf('[') + 1, myList.toString().indexOf(',', myList.toString().indexOf('['))));

    Of course I pointed it out to him that he should really go and check how it really should be done, and that his code did not work with lists that have only one item.

    After a while, he presented me his fix:

    int firstNumber = Integer.parseInt(myList.toString().substring(myList.toString().indexOf('[') + 1, (myList.toString().indexOf(',', myList.toString().indexOf('[')) >= 0) ? myList.toString().indexOf(',', myList.toString().indexOf('[')) : myList.toString().length() - 1));

    Not the first WTF I've seen in my job but definitely the most memorable one!



  •  Does that guy just not understand the term "readability?" Even if .get(index); didn't exist, he surely could have come up with something less insane.



  • I imagine this man slouching back on his chair, rhythmically bobbing his head to a groove only he can hear. The smackable smirk of an "aawwww yeeeaaah" covers up his face as he types this into his computer, thinking about what a genius he is. The masses don't deserve what I'm about to show them. I am so far above them. Check this, this will blow their minds: I'll put it all on one line. Watch yourself, Java, I'm gonna chew you up and spit you out. Awwww yeeeaah. I can't wait to commit this one into the source repo. I am stunning. I am so stunning. I am the stone cold fox of programming. That stupid PHB of mine isn't around to praise me with promotions.... typical...



  •  I think he just doesn't care.



  • @Xyro said:

    I imagine this man slouching back on his chair, rhythmically bobbing his head to a groove only he can hear. The smackable smirk of an "aawwww yeeeaaah" covers up his face as he types this into his computer, thinking about what a genius he is. The masses don't deserve what I'm about to show them. I am so far above them. Check this, this will blow their minds: I'll put it all on one line. Watch yourself, Java, I'm gonna chew you up and spit you out. Awwww yeeeaah. I can't wait to commit this one into the source repo. I am stunning. I am so stunning. I am the stone cold fox of programming. That stupid PHB of mine isn't around to praise me with promotions.... typical...
     

    You left out the accompanying comment whose content is nothing more or less than an exact duplicate of the code itself.



  • No, a duplicate of the code that was there two revisions ago, so you can never be sure whether it is the comment or the current code that better represents the programmer's intention.



  • I agree, good WTF. He should have used a database.



  • @badcaseofspace said:

    I agree, good WTF. He should have used a database.
     

    Only if it supports JavaScript.



  • myList[0]?



  • @pbean said:

    myList[0]?
    Not in Java.  You can only index arrays.



  • @bstorer said:

    @pbean said:

    myList[0]?
    Not in Java.  You can only index arrays.

     

    ...and I suppose the lists don't have a .First or .Last method either?



  • @Mason Wheeler said:

    @bstorer said:

    @pbean said:

    myList[0]?
    Not in Java.  You can only index arrays.

     

    ...and I suppose the lists don't have a .First or .Last method either?

     

    No, but the right answer isn't much longer:

    int firstNumber = myList.get(0);



  • That's a horrible implementation. He should have done it this way:

    int first;
    
    foreach(int i : myList) {
        first = i;
        break;
    }
    

    Or, even better:

    int first;
    
    for(int index = 0; index < myList.length; index++) {
        first = index;
        index = 55555555;
    }
    


  • @toth said:

    That's a horrible implementation. He should have done it this way:

    int first;

    foreach(int i : myList) {
    first = i;
    break;
    }
    You're joking, but it's totally not uncommon to see Java code like
    first = collection.iterator().next();

    In fact, a quick grep through the J2SE source finds over 40 matches for "[code]iterator().next()[/code]"   :-\

    @com/sun/tools/example/debug/tty/EventHandler.java said:

    Event event = (Event)set.iterator().next(); // Is there a better way?



  • @Xyro said:

    You're joking, but it's totally not uncommon to see Java code like

    first = collection.iterator().next();
    As a bonus, Iterator throws an exception if the collection is empty.  Can we all just agree that Java's collections fucking blow?


  • When you have a generic collection (i. e. not a list, which is ordered) there is no easier way to get a "random" item in it (or the only item if its size is 1) than iterator().next(). (or using the foreach loop in Java 1.5+)

    OTOH, if you want to have the first item, you should use a data structure that supports getting the first item better, like a list, a stack, a sortedMap or a heap.

    BTW: iterator() does not throw an exeption, only if you call next() without checking hasNext() first and there is no item left. In addition, every collection has to provide a size() method so you can check for empty lists before getting an iterator.



  • @mihi said:

    When you have a generic collection (i. e. not a list, which is ordered) there is no easier way to get a "random" item in it (or the only item if its size is 1) than iterator().next(). (or using the foreach loop in Java 1.5+)

    OTOH, if you want to have the first item, you should use a data structure that supports getting the first item better, like a list, a stack, a sortedMap or a heap.

    BTW: iterator() does not throw an exeption, only if you call next() without checking hasNext() first and there is no item left. In addition, every collection has to provide a size() method so you can check for empty lists before getting an iterator.

    Wow, that sounds intuitive and convenient!



  • @mihi said:

    BTW: iterator() does not throw an exeption,

    E next() [...] Throws: NoSuchElementException - iteration has no more elements.
    @mihi said:
    only if you call next() without checking hasNext() first and there is no item left.
    iterator().next()

    @mihi said:

    In addition, every collection has to provide a size() method so you can check for empty lists before getting an iterator.
    If only the language would pull its weight :(

    @bstorer said:
    Can we all just agree that Java's collections fucking blow?
    You think that's bad, read how the Collections designers struggle and completely fail to understand the significance of immutability: http://java.sun.com/javase/6/docs/technotes/guides/collections/designfaq.html#1



  • @JohnWestMinor said:

     Does that guy just not understand the term "readability?" Even if .get(index); didn't exist, he surely could have come up with something less insane.

     

    Denied! I reject your comment in it's entirety!

     

    Any sane developer immediately knows that you can access a list's data by giving an index of where the data is. Otherwise it is not a list. If he did not know about the .get method, or for that matter any mechanism for how to get the item, he should have immediately looked up docs or asked someone. If you say "oh but that's embarasing" I say that asking a stupid question is 100x less embarassing than having the OP's code on display in the source code.



  • @astonerbum said:

    Any sane developer immediately knows that you can access a list's data by giving an index of where the data is.
    If we're discussing List within the domain of Java, then I agree.  If we're talking in the broad list-as-a-class-of-data-structure sense, then I disagree. Although I would expect most useful list implentations to support indexing, it's not a requirement.  So if that's what you meant, then I agree again.@astonerbum said:
    If he did not know about the .get method, or for that matter any mechanism for how to get the item, he should have immediately looked up docs or asked someone.
      But solving your problems with toString is so much easier than reading or walking to another cubicle!  I signed on for a job, not a prison camp.



  • @bstorer said:

    If we're discussing List within the domain of Java, then I agree.  If we're talking in the broad list-as-a-class-of-data-structure sense, then I disagree. Although I would expect most useful list implentations to support indexing, it's not a requirement.  So if that's what you meant, then I agree again.

    I can't imagine a situation where a list shouldn't have an index. I could see it not being required, perhaps... but why would you ever implement one without indexing?



  • @astonerbum said:

    Any sane developer immediately knows that you can access a list's data by giving an index of where the data is.
     

    Well, first of all, when I had lists in CS (admittedly, we're talking late stone age, or possibly early bronze) all you got was a *first and *next, and fancy stuff like indexes was sth you had to build yourself.

    Secondly, the "SaneDeveloper (TM)" argument fails miserably, because almost every language or environment or implementation has missing features so obvious it's painful. No switch() in Perl? No inheritance in VB6? No conversion to date in MS SQL Server? No [huge list] in Java? Sometimes you just shrug and do your thing.

    All that aside: the chosen solution was of course total crap and should have set off a couple warning lights with the original developer. The least he could have done was add some comment like

    // I know this is horrible but it's 4 AM and I need to finish this and get some sleep 


  • @b_redeker said:

    No conversion to date in MS SQL Server?

    Huh? I convert strings to dates in MS SQL Server every day.



  • @blakeyrat said:

    Huh? I convert strings to dates in MS SQL Server every day.

    This is a reference to an earlier thread. You can convert to datetime no problem, but if you have a datetime and for some reason you only need the date part, you need to do some ugly hack.


  • Discourse touched me in a no-no place

    @blakeyrat said:

    I can't imagine a situation where a list shouldn't have an index. I could see it not being required, perhaps... but why would you ever implement one without indexing?
    I'd be interested in your implementation of a linked list.



  • @b_redeker said:

    @blakeyrat said:

    Huh? I convert strings to dates in MS SQL Server every day.

    This is a reference to an earlier thread. You can convert to datetime no problem, but if you have a datetime and for some reason you only need the date part, you need to do some ugly hack.

    declare @testDate as date
    declare @testDateTime as datetime
    
    set @testDateTime = '5/24/2010 14:02:00'
    set @testDate = @testDateTime
    
    print @testDate
    
    > 2010-05-24
    

    Works for me?



  • @PJH said:

    @blakeyrat said:
    I can't imagine a situation where a list shouldn't have an index. I could see it not being required, perhaps... but why would you ever implement one without indexing?
    I'd be interested in your implementation of a linked list.

    The operation is slow in a linked list, but that's no excuse for not offering it.

    Unless you're saying it shouldn't be offered *because* it's slow as a way of discouraging programmers from using it?



  •  And in queries?



  • @b_redeker said:

     And in queries?

    create table #temp
    (
    	happiness datetime
    )
    
    insert into #temp (happiness) values ('5/24/2010 14:02:00')
    
    select cast( happiness as date ) from #temp
    
    > 2010-05-24

    Continues to work as expected.



  • Ah. So again, IMTRWTF here.

    Any chance that referring to older versions of MS SQL (2000) might save me here? I even looked this up when looking at that other thread and found a long thread on another forum detailing the WTFfy ways to deal with this.



  • @b_redeker said:

    Ah. So again, IMTRWTF here.

    Any chance that referring to older versions of MS SQL (2000) might save me here? I even looked this up when looking at that other thread and found a long thread on another forum detailing the WTFfy ways to deal with this.

    The "date" type (as opposed to "datetime") is pretty new... 2005 I think? So, yeah, it's a relatively recent thing.

    Edit: you can try this fun version for older SQL Servers:

    print cast(cast(cast(@testDateTime as float) as int) as datetime)


  •  pfew... saved again.

     Anyway, so the point was: sometimes environments miss stuff others might consider obvious or even vital. 



  • @Xyro said:

    You think that's bad, read how the Collections designers struggle and completely fail to understand the significance of immutability: http://java.sun.com/javase/6/docs/technotes/guides/collections/designfaq.html#1

     

     OK, for the non-Java-users among us, what in that section makes it a huge WTF?  What I read looked pretty reasonable to me.  What am I missing?



  • @Mason Wheeler said:

    @Xyro said:

    You think that's bad, read how the Collections designers struggle and completely fail to understand the significance of immutability: http://java.sun.com/javase/6/docs/technotes/guides/collections/designfaq.html#1

     

     OK, for the non-Java-users among us, what in that section makes it a huge WTF?  What I read looked pretty reasonable to me.  What am I missing?

    Perhaps the most primary benefit is that immutability side-steps a ton of issues with concurrency. It can't be overstated how simple and straightforward immutable objects make concurrent programming. Suddenly, there are no gotchas or synchronization nonsense, nothing is changing behind your back. When you're passed an object, you're guaranteed that what you're looking at is what you've been given throughout the life of the object.
    It also has implications with defensive copying, performance, and other conceptual overheads. I'll defer the eloquent explanations to [url]http://www.c2.com/cgi/wiki?ImmutableValue[/url] and this article I just found and skimmed and it looked useful [url]http://www.developer.com/print.php/3874551[/url]. The designer of Clojure has some pretty strong words to say about immutability; I'm a supporter.

    In regards to the Collections Framework in particular, saying that they didn't want to support mutability concerns simply because it would make the class hierarchy messy reeks of laziness and misunderstanding. (So, as usual, Google picks up the slack.)



  • @da Doctah said:

    You left out the accompanying comment whose content is nothing more or less than an exact duplicate of the code itself.

    <font size="2"> </font>

    <font size="2">List<Integer> myList ;</font>

    <font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2">// alright, bear with me here. This is complicated, but together, we can get 
    through it.</font></font><font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2"></font></font>
    <font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2">// Gotta use Integer to parse the int out of the substring</font></font><font size="2">
    </font>

    <font color="#7f0055" size="2"><font color="#7f0055" size="2">int</font></font><font size="2"> firstNumber = Integer.parseInt(</font>

    <font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2">// I love substring.</font></font><font size="2">
    </font>
    <font size="2">myList.toString().substring(</font>

    <font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2">// the toString spits them out like [1],[23],[45],[678] ... pretty easy to find the</font></font>

    <font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2">// substring values right?</font></font>

    <font size="2"></font>

    <font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2">// find that first [</font></font>

    <font size="2">myList.toString().indexOf(</font><font color="#2a00ff" size="2"><font color="#2a00ff" size="2">'['</font></font><font size="2">) + 1,</font>

    <font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2">// find that comma, but make sure it's after the [ that we just found</font></font>

    <font size="2"></font>

    <font size="2">myList.toString().indexOf(</font><font color="#2a00ff" size="2"><font color="#2a00ff" size="2">','</font></font><font size="2">,</font>

    <font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2">// I love the way a million close parens look. Don't you?</font></font>

    <font size="2"></font>

    <font size="2">myList.toString().indexOf(</font><font color="#2a00ff" size="2"><font color="#2a00ff" size="2">'['</font></font><font size="2">))));</font>



  • @belgariontheking said:

    <font color="#3f7f5f" size="2"><font color="#3f7f5f" size="2">// I love the way a million close parens look. Don't you?</font></font>

     

    Oh, I see. He's a lisp programmer. That explains much.



  • @blakeyrat said:

    @PJH said:
    @blakeyrat said:
    I can't imagine a situation where a list shouldn't have an index. I could see it not being *required*, perhaps... but why would you ever implement one without indexing?
    I'd be interested in your implementation of a linked list.
    The operation is slow in a linked list, but that's no excuse for not offering it.

    Unless you're saying it shouldn't be offered *because* it's slow as a way of discouraging programmers from using it?

     

    Actually, I'd see reasons for that. Because, if your list has a "retrieve by index" operation and you need to traverse all elements of the list, the most natural approach is:

    for (i = 0; i < mylist.length; i++) {
      process(mylist.get(i));
    }

    Which is perfectly reasoneable in 99% of all cases, except for (Java) linked lists, where it transcends "slow" and turns into "painful".

    The better approach would be of course to accept that this operation is often used like that and optimize it accordingly. (Like storing a pointer to the last acessed element)

    But I guess that would be too unpure for java...



  • @PSWorx said:

    The better approach would be of course to accept that this operation is often used like that and optimize it accordingly. (Like storing a pointer to the last acessed element) use an iterator in the first place.
    FTFY.  This is why iterators exist.  They are supposed to handle the structure-specific details.



  • @bstorer said:

    @PSWorx said:

    The better approach would be of course to accept that this operation is often used like that and optimize it accordingly. (Like storing a pointer to the last acessed element) use an iterator in the first place.
    FTFY.  This is why iterators exist.  They are supposed to handle the structure-specific details.

    Bullshit.  Collections exist for the sole purpose of optimizing for loops.  Also, Java's collections need to implement pointer arithmetic.



  •  @bstorer said:

    @PSWorx said:

    The better approach would be of course to accept that this operation is often used like that and optimize it accordingly. (Like storing a pointer to the last acessed element) use an iterator in the first place.
    FTFY.  This is why iterators exist.  They are supposed to handle the structure-specific details.

    Yeah, of course, that's right. I was more thinking of the "I can't be bothered to learn Java" guys who just see .get() and jump at it, without realizing that there are iterators at all. Hey, I tried to be all real-world and stuff for a change, just like you, so don't complain :P

    Also, the concept, that Java iterators have no "current element" but instead point "between" elements is just plain annoying to work with. Apparently the designers realized this, too, when introducing additional methods. Hilarity ensued.



  • @PSWorx said:

    The better approach would be of course to accept that this operation is often used like that and optimize it accordingly. (Like storing a pointer to the last acessed element)

    But I guess that would be too unpure for java...

    Whaaat? Are you seriously suggesting that access state should be stored internal to a generic list? That's orders of magnitude worse than having mutable collections! God help you if you ever use more than one thread to access the object. That's why you use new Iterator objects! Or do you also think it reasonable to synchronize the state on every access? If you need random access, use a data structure that's designed for random access! Storing hidden state in the name of optimization is a crime worthy of death. Or a good berating. Or at least a free book on good programing practices.



  • @morbiuswilters said:

    @bstorer said:

    @PSWorx said:

    The better approach would be of course to accept that this operation is often used like that and optimize it accordingly. (Like storing a pointer to the last acessed element) use an iterator in the first place.
    FTFY.  This is why iterators exist.  They are supposed to handle the structure-specific details.

    Bullshit.  Collections exist for the sole purpose of optimizing for loops.  Also, Java's collections need to implement pointer arithmetic.

    Internal iterators vs. external iterators. Java's core mostly favors external, which I see as a flaw, but not a major one.



  • @Xyro said:

    Whaaat? Are you seriously suggesting that access state should be stored internal to a generic list? [...] Storing hidden state in the name of optimization is a crime worthy of
    death.

    Since when is having hidden state for optimisation bad? Isn't that the basic idea of caching? (When done thread-savely, I agree)

    @Xyro said:

    God help you if you ever use more than one thread to access the object. That's why you use new Iterator objects! Or do you also think it reasonable to synchronize the state on every access?

    Alright, alright, that idea was mostly for single threading settings. Though I think the actuall pointer climbing would still take orders of magnitude longer than the synchronisation. (The optimisation wouldn't do much anymore, but at least the operation would stay valid.) And if you need fast, sequential access, yeah, as you all said, use iterators.

    @Xyro said:

    If you need random access, use a data structure that's designed for random access!

    That would mean that each time I get a generic List, I'd have to check what the actual type is. How I understood it, the Collections framework was built exactly so you wouldn't need to bother with those details.

    Maybe we can agree that the real real WTF is that Java pretends that two classes with completely different runtime characteristics can be freely interchanged.



  • @PSWorx said:

     

    @Xyro said:

    If you need random access, use a data structure that's designed for random access!

    That would mean that each time I get a generic List, I'd have to check what the actual type is. How I understood it, the Collections framework was built exactly so you wouldn't need to bother with those details.

    The Collections framework isn't meant to allow you to program without awareness of the type you're using.  Otherwise they wouldn't bother with the variety of types to begin with.  The purpose of the framework is to provide a broad group of common data structures that behave in the same way, as well as common algorithms that can be applied across them.  But, as Sun themselves explain:

    @http://java.sun.com/docs/books/tutorial/collections/intro/index.html said:

    Historically, collections frameworks have been quite complex, which gave them a reputation for having a steep learning curve. We believe that the Java Collections Framework breaks with this tradition, as you will learn for yourself in this chapter. 

    Uh, guys?  There's a reason those other frameworks are complex, and it isn't because they were all designed by bad programmers while Java's was designed by a small team consisting of Donald Knuth, John Carmack, Edsger Dijkstra, and Jesus (Jesus was a junior developer).  The topic of data structures is a complex one.

    @PSWorx said:

    Maybe we can agree that the real real WTF is that Java pretends that two classes with completely different runtime characteristics can be freely interchanged.
    Well, there's nothing wrong with both an ArrayList and a LinkedList implementing a List interface.  They're both ordered and easibly iterated. 

    But in their desire for simplicity, they wound up attributed random access to all lists, which is obviously wrong.  Is it trivial to get the n-th item from any list?  Sure, but it's not a behavior of lists.  So why don't we create a RandomAccess interface for those objects that do such a thing?  Because Java makes it a pain in the ass to return something that implements both List and RandomAccess. Short of creating a bunch of extended interfaces for the various permutations, as mentioned in that article Xyro linked to, (or using Generics now, but that's got its own massive set of WTFs), it's not really feasible.

    While the ability to index a specific element is a debatable case, there are others that aren't.  Iterator, for example, promises a remove function, but not all backing collections allow it.  How can a language be so dependent on interfaces, yet still need a UnsupportedOperationException?



  • The point is, both the "right way" and the WTF way work. And while we mostly follow the path of least resistance, the WTF'or is willing to walk that extra mile to make his code shine.


Log in to reply