String.split() does it the right way. Between the s and 3, there are two tabs, and between the 3 and 4 there are three tabs. Between those tabs, there are actually empty strings. Those show up, whereas StringTokenizer simply ignores them.
Now, if you want to remove those empty strings, change the regular expression of String.split to "\t+". The + means once or more.
One way would be to use the constructor with a boolean, and make the StringTokenizer return the delimiters as well. But then you'd have to handle the delimiters as special cases. Not a nice solution at all.
The other option (and my favourite): don't use StringTokenizer at all. String.split does just what you want, and you can mimick StringTokenizer's behaviour very easily with String.split; the other way around is harder as you have just noticed.
subject: Difference between split() and StringTokenizer s nextToken()