6 ms·
As someone who programs Java a fair bit, what bad habits do you believe it teaches?
by axod 16y ago
As someone who programs Java a fair bit, what bad habits do you believe it teaches?
- wladimir 16y agoI'd like to know as well. IMO, one of the few things Java is actually good for is to learn object oriented programming. - It has a pretty simple syntax, as it doesn't have too many strange or unintuitive language constructs. - Its verboseness forces the learner to understand what is going on and be thankful for the magic that more dynamic languages provide. - It's statically typed so it forces the learner to think about types. - It's hard to shoot yourself in the foot with beginner mistakes like with C++/C. Still, it's a good preparation for learning C/C++ later. - Clear compile-time and run-time error reporting. And so on...
- smanek 16y ago- It is just barely object oriented (and Alan Kay agrees with me on this). Checkout CLOS and the MOP or Smalltalk sometime for a good object system. - No. Java has a complex syntax. Take a look at the grammar sometime. It's 10s of times longer than Scheme's (see: http://java.sun.com/docs/books/jls/second_edition/html/syntax.doc.html http://java.sun.com/docs/books/jls/second_edition/html/synta...). You just like it because it's almost, kind of, a little, like C and C++. - It is, in large part pointless verbosity. Explain to me how: Map<String, Pair<Integer, Set<String>>> data = new HashMap<String, Pair<Integer, Set<String>>>(); is useful. Explain how 20 lines for a strategy pattern or a visitor pattern is better than just having built in first order functions and multiple dispatch. - The type system is abysmal (and not sound). Runtime Erasure of generic types? Casts? Nulls? - I do agree it is better than C++ for most purposes though ;-)
- xyzzyz 16y agoComparing the languages that use S-expressions to the languages that actually have syntax is a bit unfair, I think.
- wladimir 16y ago- True; I was just considering the mainstream languages. Yes, if you include Smalltalk, LISP, I'm sure there are better alternatives to learn specific concepts. But Java is used a lot in practice, and looks a lot like other languages used in practice (C++, ObjC, C#, and friends), which in my experience makes students more enthusiastic. - I agree the "generics" are complex and overly verbose. They almost look like the C++ templated types, which I would go around with a 10 foot pole if I wanted to learn someone programming... IMO, pre-1.5 Java was best for learning. - Yes, a lot of the verbosity is pointless, I think it helps for learning to specifically mention everything and be a bit repetitive. Other languages luckily allow leaving the obvious stuff out.
- bad_user 16y agoRuby and Python are also mainstream, and both provide saner OOP. C++ templates at least have a purpose and provide extra benefits (e.g. performance, compile-time computations for pre-caching). In Java generics are practically implicit type-casts and nothing else. About verbosity ... clear conventions are a lot more effective for readability and learning. In a dynamic language like Ruby / Python, if you don't know what an object's type is or what it does, the fix is as easy as ... obj = don_t_know_the_return_type() # doing lots of stuff import pdb pdb.set_trace() That opens up a Python debugging console at the current point of execution, and you can inspect "obj" for its type / members and also modify its state. Also, if you're using "ipdb" instead of pdb then you've also got auto-completion on <TAB> (e.g. Intellisense). You can do something similar in Ruby, and in Smalltalk the whole application is active while you're typing in the IDE. There, problem solved.
- uriel 16y ago> Ruby and Python are also mainstream, and both provide saner OOP. For various other reasons I prefer Python to Java (or Ruby), but there is one thing that Java got right and Python totally messed up: avoiding the disaster that is multiple inheritance. Of course a much better option is to completely do away with inheritance like Go has done (plus Go combines some of the advantages of Python's 'duck typing' with the static type checking of Java's interfaces).
- srgseg 16y agoExplain to me how: Map<String, Pair<Integer, Set<String>>> data = new HashMap<String, Pair<Integer, Set<String>>>(); is useful. Firstly, in Java 7 or in Java 6 in a modern IDE, you only have to type: Map<String, Pair<Integer, Set<String>>> data = new HashMap<>(); So let's break this down: if I was using another language, I could just do: var data = {}; But consider what you've now lost: 1. If your code was just a simple associative array, not much. But if you have a complex nested data structure, you need to now put a comment somewhere so you don't forget what you're storing there. You can get into serious problems when multiple programmers are working on the same project if you don't clearly describe your data structures, and so you're not really saving on typing by writing Map<String, Pair<Integer, Set<String>>> because you'd have to document that in a comment instead. Since people are lazy when it comes to commenting code, Java therefore forces a degree of self documentation into data structures. 2. I notice that you're storing a Set of Strings (Set<String>). As I'm sure you know, this means you can throw a bunch of strings into the set without worrying about duplicates. In Javascript, this would be messy. Since there is no 'Set' data type in Javascript you'd have to have an associative array where you store the string as the key and 'undefined' as the value. 3. HashMap isn't the only kind of map. In Java, you could use a TreeMap so that content is sorted in key order. This saves you code later by not having to take the associative array, converting it into a list, and then sorting the list. 4. In addition to TreeMap, another extremely useful kind of map is the ConcurrentHashMap, which allows you to manipulate the Map simultaneously from multiple threads (e.g. multiple simultaneous web request threads) without getting concurrent access problems or having to write your own synchronization code. 5. Tons of other really cool data Java datastructures available to you in the Java libs. E.g. WeakHashMap which won't prevent referenced objects from being garbage collected if they are dereferenced elsewhere, and LinkedHashMap which is useful for guaranteeing the order of stored objects even if they are removed and reinserted. So although I agree that var data = {} can be more convenient in simple cases, that's not to say Java's approach has no upside.
- smanek 16y agoYes, Java 7 finally will fix this bug (which is 7 years old!). The fact that good IDEs can work around this bug, doesn't mean Java sucks any less for it though. I have similar issues with syntax for anonymous classes (which you need a lot of, to even poorly simulate fp), but we'll save that for another day. I don't want var data = {} in a statically typed language. I want something like Map<Int, [Int, Set<String>]> data = new HashMap(); to use the exact same example that I used above. This way gets all the benefits of what java currently does, with literally half the characters and more readability.
- stcredzero 16y agoIMO, one of the few things Java is actually good for is to learn object oriented programming. You'd do better in an environment where everything is an Object. (No "primitives" to get in the way.) It has a pretty simple syntax, as it doesn't have too many strange or unintuitive language constructs. Confusing language syntax and semantics? Java's syntax is pretty large and complex by any number of objective measures. Is this an instance of the "start a language war" game?
- smanek 16y agoMost of my work these days is Java too, fwiw. But only because I need Lucene and Hadoop ;-) The main bad habit is a gross overuse of patterns to compensate for language stupidity (see: http://norvig.com/design-patterns/ http://norvig.com/design-patterns/). A few particular examples include: - Too much global state. You call it a Singleton. I call it a global variable with a fancy name and a lot more code. - You lose the ability to think functionally and dynamically. You can see the core of the architecture much more clearly if your default thought is 'I want to pass a function' or 'I want to call a fn based on rutime types.' And then you should convert that to what's implementable in language X (strategy pattern and visitor pattern, respectively for Java). Thay way you don't lose sight of the forest for the trees (and can implement what you're trying to do without cruft in a good language). - Verbosity. It's bad enough that passing a small fn (1 line of code in a decent language), requires a separate class and 20 lines of code in Java. On top of that the type system is too weak to actually stop most interesting errors but just strong enough to be annoying. And for some idiotic reason, they won't even implement compile time type inference which would save lots of verbosity and maintain code/bytecode compatibility.
- kbd 16y agoI'm personally mad at Doug Cutting for perpetuating Java. Java is a virus. If Lucene and Hadoop were written in C/C++ you'd be able to easily use them from basically any language. Because they're written in Java, it forces the rest of your code to live in Java land as well.
- nickolai 16y agothere is a C++ port of Lucene (named CLucene iirc) Not sure if there is such thing for Hadoop though.
- timr 16y agoYeah, but because it's not the main project, the CLucene port is perpetually the red-headed stepchild. It runs several versions behind the Lucene trunk, and therefore, you have to choose to ignore its disadvantages. ...which is a shame, because I agree with the OP that the choice of Java was a mistake for a large, high-performance system.
- jrockway 16y agoInheritance instead of composition. Too much worry about security theater public/protected/default/private instead of actually reusing code. The inability to fake stuff for tests without designing ability to fake things into every class. Basically, you write the code, and that's what you have. If anything changes, it's basically a rewrite, even with Eclipse's "refactoring" features. Type erasure. When all you have is Java-style OO, everything looks like an AbstractHammerFactoryInterface.
- smanek 16y agoYes! It's amazingly hard to do inheritance right. As a rule of thumb, if you can't prove that the inheritance doesn't violate the Liskov substitution principle, you shouldn't be allowed to do it. (It amazes me how many java 'programmers' have never heard of lsp or a refinement proof).
- jrockway 16y agoIronically, Liskov is the exact opposite of how people do OOP. Most people subclass to add restrictions, where Liskov suggests that subtypes should relax restrictions. This means your programs work better, but you have to plan ahead.
- axod 16y agoI know I'm not an average Java programmer (I hate IDE's, hate patterns for example), but I've never seen anything as an AbstractHammerFactoryInterface. Seems like you're confusing Java the language, with how some people choose to use Java.
- icey 16y agoWould you mind discussing your development setup? What editor(s) do you use? Other software that makes writing Java easier? There are many opinions about this on the internet, but most of them are geared towards enterprise developers in large shops; not towards startups.
- axod 16y agojdk textmate / jedit / nano ant What else do you need? :/
- icey 16y agoIs it common for java developers to use a "dumb" editor like textmate / jedit / nano? I've heard that a good IDE is a requirement for writing significant amounts of Java. To be fair, I've mostly been interested in Scala; but it seems like you have to know Java to get the most out of Scala.
- axod 16y agoIt's a myth. People who don't like Java moan on that it's so verbose and the only way to get anything done is by using an IDE. Do people use IDE's to write assembly language? I'd say majority do not. You just learn to organize your code well and to be concise and tidy. A good skill to learn. My current project (Mibbit), is about 25k loc, in around 200 files. I've never had any issue working with it. I think the difference lies in if you write 'Enterprise' java, use XML for everything, use patterns, tons of threads etc or if you just write tight, tidy, concise speedy java.
- beagle3 16y ago> I think the difference lies in if you write 'Enterprise' java, use XML for everything, use patterns, tons of threads etc or if you just write tight, tidy, concise speedy java. There's a saying, "one of the problems that lawyers have, is that 95% of those in the profession give all the rest a bad name". That's also true for people who view Java. notch's screencasts show that there is an alternative, and I'll take your word for it that you're in that class as well. But you're part of the 5%; maybe the 1%.
- beagle3 16y ago- Strong push towards threading. Before NIO, there wasn't a way to avoid threads if you wanted to talk to multiple sockets. NIO has solved that for networks, but the whole java framework/idioms push you towards threads where it shouldn't. - No way to tell how things are implemented. I had written a heapsort in Java. It run x40 slower than the equivalent C. I was trying to figure out why -- e.g. was it inlining the things it should? if not, why? It's like Java is a subcontractor that won't answer about their methods - that's a bad habit.
- axod 16y ago> Strong push towards threading. Before NIO, there wasn't a way to avoid threads if you wanted to talk to multiple sockets. NIO has solved that for networks, but the whole java framework/idioms push you towards threads where it shouldn't. Where? I'm starting to think people dislike Java for the community / way it's used in enterprise rather than anything to do with the language. There's no push toward threading in the language :/ And NIO has been around for years. - No way to tell how things are implemented. What?? Look at the source code. Decompile the class file into byte code :/
- beagle3 16y ago>> Strong push towards threading. Before NIO, there wasn't a way to avoid threads if you wanted to talk to multiple sockets. NIO has solved that for networks, but the whole java framework/idioms push you towards threads where it shouldn't. > Where? I'm starting to think people dislike Java for the community / way it's used in enterprise rather than anything to do with the language. There's no push toward threading in the language :/ And NIO has been around for years. I've used Java (and was burnt by it) before NIO made its appearance -- it was 2002 or maybe even 2003. I recently had to join a Java project that's "only" been around 2 years, so it could have benefited from the years of NIO -- but other than the base language, there is no async interface to be found. You want to talk to a database or key value store? You have to block (meaning thread). Want to do a URL fetch? you have to block, because there is no non-blocking libraries to be found. It's not that it is impossible to do -- it is quite possible -- but it is almost against java culture. > Where? I'm starting to think people dislike Java for the community / way it's used in enterprise rather than anything to do with the language. You can say that again! The java language is, I guess, ok (I don't like it, but it's mostly a matter of taste). The java ecosystem encourages verbosity-for-verbosity's sake, engineering-for-engineering sake, and ignoring common sense in the name of "purity". That Java project I joined, for example, has hundreds of classes that do nothing but store a field or two, have getters and setters for them, and perhaps have one "action" in them. Each such class is only a couple of hundred lines. This is totally useless, and when optimization time comes (and it comes, because the project is running too slow because of hundreds of layers of encapsulation), it is nearly impossible to find a culprit because everything is spread thin through hundreds of useless classes. I put up a plea for good java code on HN a few days ago: http://news.ycombinator.com/item?id=2094274 http://news.ycombinator.com/item?id=2094274 it didn't get high enough to ellicit much response (20 on the "ask hn" page, not sure how far on the main). But the responses that are there did not cause me to re-evaluate. > - No way to tell how things are implemented. What?? Look at the source code. Decompile the class file into byte code :/ I have a merge sort that takes 40x long as it does in C. The reason I needed to implement it myself is that for the 400MB of data I'm looking it, the library tried to allocate over 2GB (which is all the deployment machine has), and that's just my test data -- when I try to sort 2GB of data, it would have required ~10GB. I carefully wrote it so that no object gets allocated during the sort. 40x slower than C. WTF? Perhaps that MemoryMappedByteBuffer I am using does not inline it's ".get()" method -- that would explain x5, I think, not x40. But I have no frigging way of checking. I am doing high performance code, which I agree is not common, but my experience with Hadoop (which is becoming ever more popular) is that the design decisions are such that the performance cost is x10 for just using hadoop compared to writing straightforward code -- meaning you would need 10 nodes to just break even. I've been burnt by Java. I came back only after I could treat it with an open mind. I've been burnt again. I hate Java.