Hacker News new | comments | show | ask | jobs | submit login
Java language oddities (javaworld.com)
56 points by osopanda 9 months ago | hide | past | web | favorite | 35 comments

Some time ago my Java app stopped showing notifications. I looked at the code and discovered that I accidentally posted URL before the line that shows notifications:

http://example.com/ showNotification();

It compiled without problem because http: is label and // commented out the rest of the line:)

If had a similar issue (in C) that took me at least an hour to find:

   switch (whatever)
       // code
       // code
      // code
i.e. accidentally using labels instead of "case E_START:". GCC at least had the decency of generating a warning about unused labels, while I suppose `javac` does no such thing.

Just tested in my Eclipse project

This mistake (unsurprisingly) isn't possible in Java:

"Syntax error on token "{", case expected after this token"

With an unused label I get the warning "The label E_START is never explicitly referenced"

A good software process prevents these types of errors. You shouldn't have any warning in your project at all, and if you see one you'll know to check it out. You should use @SuppressWarnings for any warnings you have reviewed and have determined are not errors. Your IDE should mark warnings clearly at the project level, the file, and the offending line. They also should have an overall list of warnings (and errors) and you should go through them before building a release.

I rather like the JPL rules which say that code MUST compile with NO warnings even if the warning is wrong. See rule 2 in https://lars-lab.jpl.nasa.gov/JPL_Coding_Standard_C.pdf.

I’m confused by “listing 5” that states private methods and variables are accessible without reflection. The example it gives shows a static main within the same class that declared private.

That’s the definition of private, that only the declaring class can access. I believe the main beef is that one object _can access_ another object, even though they are the same type. That makes perfect sense to me. How else would equals and hashcode work?

I can see both sides of the coin. It would make sense if the only way to depend on an instances hidden values was through its public interface. That way, each object is a truly independent actor, specified by and only by its public interface. You and me both belong to the general class of humans, but you still have to ask me if you want to borrow my money.

I desperately need better nomenclature, but it is essentially what I think of as "implementation hiding for security and reliability reasons". You specify a small-ish set of methods that depend on the internal state of only this object, you verify their goodness, and then calmly implement all other operations in terms of those.

Then Java is based on "implementation hiding for maintainability reasons" -- i.e. it's really important that if you refactor something private in a file, your commit should only have to mention that file, and no other file can depend on private members in other files.

In this case, the "reliabiliy" perspective confers greater maintainability, at least in one dimension. On the other hand, much lower flexibility, as several people have mentioned already.

In some loose sense, it's the distinction between a syntactic perspective (boundary crossing happens at the file level; the characters on screen determine what implementation hiding means) and a semantic perspective (the objects should occupy an utopia where they do not distinguish between each other based on class, if you excuse the pun. What matters is their allowed behaviour and that interaction.)

I am afraid I have failed to express this in neutral terms because of my preexisting biases, but I hope the idea comes across anyway.

> That makes perfect sense to me. How else would equals and hashcode work?

It also makes perfect sense to me. Visibility is type-based, not instance-based. But to answer the hypothetical question: one would have to introduce class-private (package private?) getter methods for all relevant truly-private fields. I'm happy that's not the case.

I was surprised either. What I find odd:

"protected" stuff can be accessed by classes in the same package, even if they not inherit the class with the "protected" member. I find this very annoying as I use protected and package-private for entirely different semantics.

No scope qualifier means package-private for classes and public for interfaces. I never could wrap my head around this. That's bad user interface design. As well, I have package-private interfaces sometimes (which is perfectly possible), but their methods can only be public (which is unwanted if the interface is package-private).

It's commonly called "inheritance anomaly".

"Inheritance anomaly" is something else. It refers to the combination of inheritance and concurrency not working out well together.


Bytes being signed is the ultimate Java oddity. Can't say how many times I've been bitten by this.

I also don't like it.

Legend goes that Gosling went around Sun offices and almost everyone failed to get unsigned versus signed math right, so they went with signed only types.


> Quiz any C developer about unsigned, and pretty soon you discover that almost no C developers actually understand what goes on with unsigned, what unsigned arithmetic is. Things like that made C complex. The language part of Java is, I think, pretty simple. The libraries you have to look up.

At least Java 8 introduced unsigned math helper methods.

> so they went with signed only types

Except chars

> At least Java 8 introduced unsigned math helper methods.

They still aren't enough IMO. They don't have way ways to take LE/BE bytes out of integers or vice versa (not worth creating ByteBuffer for). I always end up recreating these utilities in projects where it isn't worth depending on or shading an entire Guava, e.g. [0]

0 - https://github.com/cretz/javan-warty-pig/blob/master/fuzz/sr...

Yep, lack of unsigned primitive types belongs to my list of Java pet peeves.

I’m not sure he was right about that. Sometimes you want unsigned types. If you only have signed types, you have to use them, but you might forget they’re signed. That’s almost certainly what caused this bug to be introduced, which will now never be fixed due to backwards compatibility: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=7025832

Yea, I've seen that explanation before, but it smells a lot like "postdiction" where you make up an explanation after the fact. I find it very hard to believe that "almost no C developer" understands unsigned arithmetic. And I'd doubt you'd get any argument from someone who understands both signed and unsigned, that signed arithmetic is the harder to understand of the two. But, even if he were correct, it still doesn't make sense, as abstracting away the complexity of common operations is exactly what high level languages are for.

Signed bytes are really really annoying in practice, and I can't say I ever wanted them as opposed to unsigned bytes. I wrote up about them a number of years ago: https://www.nayuki.io/page/javas-signed-byte-type-is-a-mista...

Wow. That is weird. I didn’t realize that. But then again, the only time I’m dealing with bytes in Java is for file reading. With the latest use having it wrapped in a Guava ByteStream.

I have to ask, why would you be trying to, I presume, be directly manipulating bytes in Java?


Video / audio codecs.

Cryptographic algorithms. (encrypt / decrypt, hash functions)

Cryptographic random number generators.

Ordinary random number generators.

PKI (key generation, validation)

Packing / unpacking binary structures used in wire protocols or message formats. (Example: a certificate, public key, jpeg, protocol buffers)

Implementing things like Protocol Buffer. (Language neutral binary format)

Implementing BigInteger. JDBC drivers.

Java libraries that create, compile, decompile or otherwise manipulate Java Byte Code.

Java libraries that create or manipulate other types of binary executable code. (eg, an EXE file)

Implementing Class Loaders for java.

The reasons you might work with bytes in Java are as endless as why you would work with bytes in C or any other language.

Oh yah, that’s right, I forgot about those since I’ve never implementing those things by hand before. I have used almost all of the list at one point, but never had the need to dive down and write my own and always have been fortunate to benefit from a great library or two to help out.

Thank you for the reminder!

Embedded development, image manipulation, network protocols, parsing binary files...

Java is my main language, but not for those things if I can help it. For network protocols for example, I’m a big fan of Netty.

Thanks for answering!

I’m sure you’re aware of all this and I don’t want to backseat drive/code. It’s just I was on a project once where microsecond latency mattered and it was written in Java, but with a custom String class and custom garbage collection (using a custom object pool instead of relying on JVM’s to avoid any GC halt, which would be intolerable). It was a really fun project tech wise, but at that point, C/C++ would have made wayyyyyy more sense and saved us a lot of headaches.

There are plenty of options available in that domain.





Then there are the Java variants out of Mountain View, although Android's performance is not in the same league as those ones.

This are just the most well known ones, Java is not only the OpenJDK.

As for microsecond latency, I guess it matters a lot to the US military.


"PERC Ultra offered Lockheed Martin the responsiveness it needed to meet its most demanding timing requirements. In addition to real-time threading and deterministic garbage collection, PERC Ultra provided the instrumentation and VM management tools necessary to support the mission-critical real-time requirements of the Aegis Weapon System."

"The Lockheed Martin-developed Aegis Weapon System is the sea-based element of the U.S. Ballistic Missile Defense System. The Aegis Weapon System is a radar and missile system integrated with its own command and control system, capable of simultaneous operation defending against advanced air, surface, and subsurface threats."

Err... Maybe not microsecond latency ? Yes PERC is AOT, and real-time (if you call sched-fifo and preempt_rt on Linux real-time) but consistent microsecond (!) latency on something other than microcontroler/dsp/fpga hardware and with PERC, I'd like to see. My experience says more likely millisecond latency, which is good enough for most radar applications (you'll have dedicated fine-tuned nanosecond-capable hardware for high quality rx / tx anyway)...

Edited: but Yes, and they're not the only ones that did radar or embedded software with PERC. There was a time (5-10 years ago ?) it was all the rage...

Thanks for the clarification. My knowledge is related to papers and articles.

You say you're a big fan of Netty. It's developers probably had to work with bytes in Java.

The way private visibility is handled is actually pretty useful for data-structures like Linked-Lists or trees where one creates more of itself and needs to adjust internal pointers without providing an external interface for anyone else to do so.

Java Puzzlers[0] has a few entries similar to this. Some of the entries are things that would trip you up (but logically makes sense) rather than oddities, but it's an interesting read. Note that the book is from 2005 and uses Java 5.

[0]: https://www.amazon.com/Java-Puzzlers-Traps-Pitfalls-Corner/d...

You can also search YouTube for "Java Puzzlers" for a few talks by Josh Bloch (the author) where he goes through more puzzlers.

Many more Java language oddities are pointed out in the book "Java Puzzlers". One of its authors is Joshua Bloch, a major contributor to the Java language and libraries. http://www.javapuzzlers.com/

as far as oddities are concerned, what about java.lang.NullPointerException for a language that is free of pointers ?

Thinking about this:

For 'Object x', x is nothing but a (typed) pointer.

Pointer manipulation is heavily limited, but technically, Java has pointers.

it's a reference, not a pointer (fe, you cannot get its value/address), so it should have been NullReferenceException or NullDereferenceException (or something similar)

You can get its address via the unsafe package, and Panama will provide an alternative API to do it.

C# named their version right: NullReferenceException.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact