1

I had this crazy initialisation --

documentList = new ArrayList<Map<String,Integer>>();

which I intended to store a new map everytime in a loop but unfortunately put itself inside the loop. And you know the havoc.

How do you detect such mistakes? I might be looking for suggestions on 'recommended debugging techniques' but am also looking for more expert advice

  • 4
    In a question about looping, it would help to see the loop in addition to the data structure. In all likelihood, you are coding some primitive function like `map`, `filter`, or `reduce` or some combination of them as a loop. Java 8 will have these primitive functions. Scala and Clojure have them already. – GlenPeterson Nov 19 '13 at 13:11

3 Answers3

8

These mistakes are detectable by the system and simple to avoid: embrace immutability.

At least declare your documentList as final. This immediately causes the compiler to inform you about this particular error. Unfortunately, Java does not have all the good things from functional programming, like real immutable lists and higher-order functions (yet), but at least final means you cannot replace your initial list with a completely new one. You can still make mistakes like calling documentList.clear(), but those are much less likely to happen by chance.

Hence, as usual, I try not to even go down the road of having to detect such mistakes, but I try to write code in a style that immediately ensures such a mistake cannot happen at all. For good reasons, mutability is spelled as t-r-o-u-b-l-e, so never walk that road unless you have to. The more parts of your code that can be declared final, the better.

Frank
  • 14,407
  • 3
  • 41
  • 66
2

The best way to catch such bugs is to prevent them from rearing their head during runtime. You can achieve that in several ways (which are not mutually exclusive):

  1. Write your code in a style that allows a compiler to pick up on the errors. Some examples are to make liberal use of immutability (const/final, as also described in the answer by @Frank), or to write equality test like this: 42 == x in a context where assignment would also be legal.

  2. Have a second pair of eyes look over your code (as in, perform a code review).

Bart van Ingen Schenau
  • 71,712
  • 20
  • 110
  • 179
-3

In general you should write unit tests for preventing mistakes. With test driven development you build your components in small increments and constantly strengthen your test harness. As a result you have a more-or-less bug-free component which you don't need to debug afterwards.

Muton
  • 617
  • 4
  • 11
  • Why the down-vote? If you consider unit testing and TDD as a bad idea then please elaborate. – Muton Nov 19 '13 at 10:28
  • Errors in loops are often subtle, particularly in code which uses mutability and side-effects. While it is usually easy to write unit tests which test boundaries and simpler edge cases, it can be hard for them to find errors which may only manifest in repeated iterations over a dataset. For that you would need something more like QuickCheck. Even then, while it will detect an error in the output, it can't point you at the cause. – itsbruce Nov 19 '13 at 10:29
  • 1
    Muton, you acknowledge you didn't really understand the question and your answer is not very useful to the specific case given, nor even as useful as you think in the general case. – itsbruce Nov 19 '13 at 10:30
  • As a non-native speaker I think the question is badly worded and initially it was hard for me to understand what it was all about. But now that I do, I argue that a very basic unit test with fixed data would catch the issue. – Muton Nov 19 '13 at 10:42
  • How can you say that, without having seen anything but a variable declaration? – itsbruce Nov 19 '13 at 10:51
  • 1
    The problem is that the OP put the variable initialization inside a loop causing the list to be cleared on each iteration. What he wanted was to initialize it outside the loop and then populate it in the loop. A simple test with more than one element in the data-set would reveal this bug. – Muton Nov 19 '13 at 10:55
  • 4
    Again, you assume a direct correspondence between this block of code and the output of a library or api call. Your advice is generic and applies equally to any coding error. It says nothing about how to *avoid* this particular error nor does it even give good advice about how to *detect* it (as I said, a test platform like QuickCheck is much more likely to detect this class of errors than unit testing). – itsbruce Nov 19 '13 at 11:50
  • As I say in my answer in TDD you implement your code in small increments which basically leads you to writing highly modular code. In this process you would write an isolated test for that particular piece of code and as a result it would not have the error in the first place. Yes, it's generic advice but it would prevent this particular issue and you would surely detect your error the moment you do it. TDD is more than just having unit tests, it's a way of working. – Muton Nov 19 '13 at 11:59
  • If you don't understand by now why Frank's answer was voted up and yours down, I don't think you ever will. Signing out. – itsbruce Nov 19 '13 at 12:07