loading...

Why not Java

davidsackstein profile image david-sackstein ・3 min read

Holy Wars in our profession are all too common. Proponents of different ecosystems find it hard to agree on which method, discipline, language, operating systems and toolsets are superior.

Our judgement of ecosystems with which we are not familiar is heavily influenced by prior knowledge and experience. In order to appreciate the strengths of what we do not use, it is often not enough to learn more about them, but also to accept different perspectives and approaches and to judge those systems from these different perspectives.

I realized this many years ago when learning TDD.

At first, TDD seemed preposterous, unreasonable and impractical approach to developing software, but today I use it readily whenever I get the chance.

Learn the technicalities of TDD took no time at all, but that was not enough for me to see its strengths. What made the difference for me was a deeper understanding of the importance of requirements analysis and of testing and refactoring in the development process. Once those were understood, TDD quite naturally became the sharpest tool in the box.

I had a similar experience when I finally sat down to study Functional Programming. Unlike TDD, there is a lot to learn in FP. But FP only became an important tool for me when I finally grasped the concepts of immutability and functions, the importance of function honesty and the play between Functional Programming and Object Oriented Programming. In order to use Functional Programming effectively, you need to approach a problem differently. When you do, the Functional Programming tools will help you solve it.

I open with this idea in order to convince you that I sincerely prepared myself for such an epiphany when I embarked on my journey with Java about one year ago.

I have many years of experience using .Net (C#).

In those years I have learned to admire the power of the entire ecosystem: the languages, libraries, tooling and maturity. I have found that it allows me to concentrate on the job at hand and helps me write high quality software quickly. .Net also keeps up to date with the latest trends, adding new functionality without increasing the complexity of existing code, allowing me to learn about the latest engineering practices from the ecosystem itself.

.Net is truly a masterpiece of engineering.

I am also no stranger to Java. But until a year ago, I had not used Java for any commercial project. For years, I have been observing the Holy War between the .Net and Java communities from the sidelines.

The Java community claims that its ecosystem, which is much more widely used than .Net, is at least as powerful as that of .Net. Java has the additional advantage of being OS independent and is supported by a larger and active open source community.

I have always had my doubts though. From what I had seen of the language, it had far fewer features than C# and the ecosystem seemed over-complex for my liking.

But now I have no doubts. A year after my journey started, I can say that the epiphany never occurred, and for me the dilemma is over.

The Java language is weak. The ecosystem, in particular that of Spring Boot, is fragile and difficult to maintain. There are too many ways to do one thing and very often, only one (if any) works, leaving the developer to repeatedly apply trial and error in a desperate search for a solution.

In the link at the bottom of the post I explain what brought me to these conclusions.

But one further note is worth mention.

I approached my study of Java with an open mind. At every choice and junction I consulted with experts, studied online courses and read posts online. I tried to make all my decisions align with the Java approach, and not with my habits from .Net.

I came to Rome to learn from the Romans.

Enjoy reading more at this link:

https://drive.google.com/file/d/1Z8rsBh-xNA3uHfR1V9CHO9V2jWIu2yuY/view?usp=sharing

Discussion

pic
Editor guide
Collapse
mt3o profile image
mt3o

2) Java has introduced Streams (similar to LINQ in C#) to make it easy to manipulate iterables in a functional, declarative way.
But an Array in Java is not an Iterable (and neither is a HashMap).
Java 8 enables you to convert it to an Iterable by implementing a functional interface and Guava is a third part library that does that for you but it is not part of the language. This probably has a performance impact, but it also makes the work of collecting streams and converting them to arrays just that much more difficult to do.

For me - you misunderstood like everything. I could debunk what you wrote, but, forgive me, my time is limited and I have better things to do.
In this little block of text you put so many misconceptions and false assumptions - I don't even know where to start.
Regarding streams, they are much more than LINQ-analogue. For starters, they are an interface that can (should be and is!) implemented by 3rd party vendors. That's awesome. You can issue i.e. SQL query with streams without touching sql. In my work I use streams to build queries carried over by TCP, and the querying command is built upon the streams.
From this point - one must address your claim that "java is weak". Oh gosh, I imagine you rising similar claim against C/C++... This claim has similar level of truthfulness. Not covering 100% scenarios is nothing against the language itself. It's not even a thing for the language, but for its standard library. Yet, again, I'll repeat, you could rise the same argument against C, python, ruby, anything. Well, perhaps, except c# running on dot net bloat. But wait, how many TDD frameworks are there? ORMs? Window building toolkits? I stopped using when Silverlight was cool. What happened with it?

Arrays? Being iterable? What for? If you want to have iterable backed by rawxarray, use ArrayList. Iteration over HashMap? First question: in what order? This collection is designed to store data with quick random access for a given key, not for iteration.
You mentioned Guava, said it's not part of "language", again proving you don't understand what you write about. When we talk about something, we should share the common dictionary. Language doesn't include libraries. Java as language specifies what are the opcodes, not the classes, they belong to the standard library, which is JDK. No library is part of the "language". By definition. It can be part of the standard library, in regards to java - the JDK, nevertheless belonging to jdk or not it doesn't affect the performance. And if we are talking about Guava, not knowing it makes you crippled. They provide some great and performant libraries, like for example, the ConcurrentHashMap.

You'd feel in similar way if I wrote that C# has no good logging tools because Console.out is difficult to use for a long term. That's BS.

Please, learn how to use something before you critique that thing.

Collapse
davidsackstein profile image
david-sackstein Author

@mt30 as I am not a Java expert I may have made a few mistakes in terminology.
But I do not think that your comments address the essential issues I raised.
If you like, we could select one point and discuss it in more depth.
I am open to retract my conclusions and others might benefit from the discussion too - but you say you do not have time for that.

Collapse
siy profile image
Sergiy Yevtushenko

Well, many "issues" are not issues but plain lack of knowledge. "Issues" listed as "language weakness":

  1. There is a comprehensive time-date-calendar framework in JDK. It's part of standard library for many years. Once it was added, I never had any task which involved time or date manipulation which would require any external libraries.
  2. You're mixing up two different things: Iterable and Stream. From the language standpoint Java arrays are Iterables, since you can use them in enhanced for loop (like for (Type value: iterable) {} ). And you can convert array into Stream using Arrays.stream(). And, well, Java is not a Microsoft thing, there is no point to expect that something will have performance impact just because it's not a part of standard library.
  3. Every lambda type in Java corresponds to interface with single abstract method. This is the single, unified standard way to define lambda types. Functional interfaces already defined in standard library are for your convenience, but if you don't like them or don't want to search them, nothing prevents you to create your own. No point to complain and no "issue", just lack of knowledge.
  4. Must admit that I'm happy that Java has no async/await as part of language. There are two significant reasons for that:
    • These keywords is a huge reverence to imperative style. They result to non-composable, hard to read and maintain code. In contrast, Promises/Futures enforce functional, composable code style and don't need language level support.
    • Presence of such keywords would mean that this feature is locked to single implementation which not necessarily is the best one or completely fits my needs.

Remaining "issues" are of the same quality.

Thread Thread
davidsackstein profile image
david-sackstein Author
  1. There are more than one frameworks for describing time in Java and that is in itself a problem. I have not found one that provides the minimum I need easily. For instance, how do you construct a Date from its components, and how do you decompose it again. You need to start creating CALENDAR instances and so on. Of course it can be done, but it is verbose and messy. But even if I find the one and best, it is not easily compatible with the others. When you need to call other libraries that take Instant and you have Date or the library uses LocalDateTime and you have Calendar. Managing these conversions and the intricacies of each object are time consuming and shouldn't be.
  2. I am not an expert, but I am pretty familiar with Streams by now. I recommend you take a look at IEnumerable in .Net. with LINQ. I think you will agree that Streams are a very poor imitation of what can be done in a modern language. LINQ provides a functional language over all IEnumerables in a more succint and unified way. Streams are bogged down by the fact there is no support for extension methods in Java and that there is no one interface to describe all collections. Even creating a Stream is a big deal. To create a stream from an array you have to explicitly call Arrays.stream(). Collecting streams is a big hastle often requiring combinations of static Collectors methods instead of a simple toArray or toList.
  3. Lambdas in Java are second class citizens. They are just replacements for interfaces. In order to use them you have to use a predefined interface type that matches your lambda signature. The most common ones exists, but you often need different ones (e.g. a lambda that takes 3 parameters, returns one and does not throw exceptions), and even if you have one that matches, you are forced to call its particular method (apply, supply or what not) which may not be intuitive in the context you are using it. In other languages, a lambda is a callable type and you call it with () just like a method.
  4. Async/Await is extremely powerful and is missing in the language. The poor support for this kind of concurrency in the language has lead to a plethora of Future libraries springing up to try to fill the gap. There is no disadvantage at all in locking you into a single implementation if that implementation is done well by the language developers. Implementing async await behavior is extremely difficult and I dont think you should be wishing you had the freedom to write it yourself. You might not do such a good job. (Maybe you will, but most people wont) ------ Since writing this post I have got to know Kotlin quite well and I can say that it does provide solutions for many of these issues over the JVM. The fact that JetBrains saw the necessity to implement lambdas as other modern languages do, to add the concept of sequence and to add extension methods is testimony that the many of the weaknesses that I have outlined in my post are indeed great drawbacks in the Java language that needed to be addressed. Unfortunately Kotlin still suffers from the terribly complicated dependency management issues that it inherits from the Java ecosystem, but as a language it is a great improvement.
Thread Thread
siy profile image
Sergiy Yevtushenko
  1. Date class is an old-fashioned way to work with date and time. There is a new java.time framework designed after Joda Time, one of the best tools dedicated to this topic.
  2. Java is not .Net and don't have to be.
  3. Lambdas in Java are replacement for anonymous classes. And like classes lambdas are first class citizens. If you need lambda with 3 parameters - create appropriate interface. What's the problem?
  4. As I told you, they harmful. And lack of them can't lead to any library since this is language level feature. As of asynchronous support, Java has CompletableFuture in standard library. This is, perhaps poorly named, but otherwise exceptionally good Promise implementation. So, there is no gap to fill. Nevertheless I'm happy that there is such a freedom since I wrote a replacement for CompletableFuture (and underlying scheduler). One of the reasons - my implementation uses Linux io_uring asynchronous I/O API which is only about a year old. Why should I wait for language developers if I can do that by myself?

As for Kotlin: it has couple of interesting ideas accompanied with pile of poorly thought out code size reduction hacks. Overall mix results to significant mental overhead which negativity impacts productivity, despite claims. By the way, it doesn't solve any real Java issues which Java unable to solve by itself. On the other hand, it might fit better to your expectations as it provides many useful tools to create mess in codebase, freedom to put any class in any file and extension methods are among them.

Collapse
mt3o profile image
mt3o

Misunderstanding difference between standard library and language itself is beyond your issues with java.

I opened your post to learn some actual issues with java. I don't know, something about cold start, about size of "fat jars", about where java lies behind scala/kotlin/rust/erlang/lisp. Something about abuse of reflection, agents, ineffective practices of defensive programming, performance impact of Optional<> ... Instead you wrote that using guava might affect performance because it's not part of jdk... It's trivial to benchmark this. But checking it requires acting professional, being objective. Using such half baked claim against whole language is just unprofessional. Taking on the point that packages are useless, and final argument was that IntelliJ generates import statements for you - that's laughable. I don't even how to address this, where to start with explaining why you are wrong, except for treating you as a total beginner. I don't even know where to start and I feel helpless, that's where the laugh comes from. This is what made me feel offended.
In my understanding, you are disappointed that java is not c# (assumption: backed by dot net package appropriate for 2019) with it's main (?!) IDE not being copy of Visual Studio.
Not to mention, that NetBeans or Eclipse have more right to be called the main IDE for java, Eclipse for being older, NetBeans for being provided by Sun/Oracle.
Do you even know that for years the best refactoring toolkit for VS was made by JetBrains? The guys behind IntelliJ?
You wrote pretty huge document about where java falls short, but for the part I read - you focus on parts where you don't know how to use it, dont understand what you do, and regret that it's not c#. Understand my disappointment. I expected much more, given the fact you published the document on separate URL, as a word document, and you publish it using your real name. On the contrary I'm just an anon around the internet and can change the nickname whenever I want.

On the other hand I can add fair share of criticisms for c#, like I don't get why I can incre the performance by order of magnitude by marking blocks of code as unsafe, unrolling the loops and inlining getters/setters. Has Microsoft done something with that since 2014 when was the last time I done something with that ecosystem?

Don't get me wrong, if you take another approach to the subject, I'd be glad to read your article and respond to it.

Thread Thread
davidsackstein profile image
david-sackstein Author

@mt30
I find that anonymous writers are more likely to make personal comments and use offensive language.
As we are not making any progress I think we should just agree to disagree and end it here.
Don't get me wrong, if you take another approach to the subject I'd be glad to have this discussion with you.

Thread Thread
mt3o profile image
mt3o

To start making progress, acknowledge what I wrote, because I put few (or even a dozen) screens of text which you completely ignored, dismissed by calling it personal and offensive. Refer to what I wrote, not to your feelings. To illustrate up your zero level of attention on what I wrote, you can't write my nickname properly. :(

Thread Thread
davidsackstein profile image
david-sackstein Author

I acknowledge you made some good points - which I can refute.
But you also used the terms laughable, "total beginner", "unprofessional", "half baked claims" and the like.
So let's just agree to disagree.

Collapse
vmrocha profile image
Vinicius Rocha

Hi David, you are bringing in good points.

I am, like you, a long-time .NET developer. And long ago, when there was a religious war between Java and .NET, there weren't many ecosystems like we have today. JavaScript was not that strong, Python was not as much used as today, functional programming was only used academic, and so on. And, .NET was not always open-source, not multi-platform, and the community was not so strong as it is today. That said, most of the design principles that we use today in Object-Oriented programming, came from the Java community. Most of the great Object-Oriented names we know today came from there.

I am sure that there are still a lot of knowledgeable people doing great software using Java, and there is also a lot of legacy code in Java out there. I believe that they brought a lot of knowledge and experience to the table, that the .NET team and community was able to benefit from. Microsoft was very smart to take the good bits and, for me, the decline of Java became when Sun was acquired by Oracle.

Choosing one over the other, most of the time is a business decision that depends on the software/tools and expertise that you already have inhouse. You might not want to start a new .NET team that is not able or will not be happy to maintain your huge legacy Java code. And I see nothing wrong starting a new software using Java if you know what you are doing and will be happy with it.

I am not confronting your opinion, just expressing my own.

Collapse
davidsackstein profile image
david-sackstein Author

Hi Vinicius Rocha,
You raise good points. I think that Java created a revolution in the 90's and introduced many important ideas that we still benefit from today. And indeed, I think Microsoft leveraged that knowledge to build an even better system.
In fact, the only difference of opinion we have is what the considerations for choosing Java over .Net for new projects might be.
You say that it is a fair decision if you know what you are doing. Unfortunately I think that this is not enough, because you need to know too much to make your development as smooth as with .Net.
I would say that it is a fair decision to choose Java over .Net for a new project if you know what you are losing :)

Collapse
vmrocha profile image
Vinicius Rocha

"if you know what you are losing" I like that! :)

Collapse
mt3o profile image
mt3o

2) Package visibility boundaries are only as strong as class level visibility.

And this claim is either a bold lie or proof that you don't know what your writing about. As with pre- as with post-java9 restrictions.

In some point you wrote about packages as encapsulation, showing lack of knowledge of class loaders.

Yet, the masterpiece argument against JAVA is here:

3) Package imports are effectively not explicit (...)
But in Intellij you never actually write your own import statement.

ROTFL / PEBKAC

Collapse
davidsackstein profile image
david-sackstein Author

I don't think laughing (as in ROTFL) is very productive criticism.
You seem to be offended by my judgement of Java, and none was intended.
There is something more you should be aware of.
One of my main criticisms of the ecosystem is that you need to learn a lot in order to use the framework effectively. The more areas you think I need to study actually emphasize this weakness.
True, as professionals, we should learn whatever we need - in depth - as needed. But I think that .Net shines because, you need to learn relatively little to get things done.
There are much fewer surprises.
But let's not bicker about this.
If you care to spend the time to explain your points in more detail, and you are willing to listen, and possibly learn too, then let's continue this discussion.
If not, I respect your opinion, but see no need to change mine.

Collapse
siy profile image
Sergiy Yevtushenko

I really don't understand what's wrong with need to learn a lot to use huge framework effectively? I'm pretty sure that if .Net has frameworks of similar size and coverage, they also need a lot of efforts and time to learn. This property is not language specific.

Thread Thread
davidsackstein profile image
david-sackstein Author

As a developer I want to focus on the tasks at hand and to learn as little as possible so that I can get the job done effectively.
.Net is also a huge framework, but when you learn one part, you often find that others follow the same pattern and the incremental learning effort is small.
And its not just about learning. The costs of working with a disparate ecosystem that has no clear direction or consistency is enormous and is often just a question of trial and error. It is not just learning. It is often guessing.
I have been through this so many times in the last 2 years. You want to make a small change, you need to upgrade a library. You find it is not compatible. You need to upgrade something else. You get cryptic error reports. You scan the internet for help. You find many, many developers with the same problems. Each suggest there own solution. None work for you, then you find mention of a tiny detail somewhere that you think might help - and it does. But it is brittle. You find that you cannot do A and B and C and everyone who says they succeeded to do so were using B v2 but you are on v3. And should it make a difference? Yes? No? Guesswork.
With .Net it doesnt work like that. You download the sample and F5 and it works.
This is not about learning a huge network.
It is trying to cope with a brittle ecosystem that has little consistency and spending hours of trial and error.
Try upgrading from Spring Boot 2.1.3 to 2.3.4 all hell breaks loose.
Try getting to use Junit 5 when working with Spring Boot. Good luck with removing the transitive dependencies on Junit 4.

Thread Thread
siy profile image
Sergiy Yevtushenko

I see no point to transfer your bad experience with Spring to whole Java ecosystem. I have my own set of painful stories related to Sprint.

Collapse
mt3o profile image
mt3o

Btw, Java doesn't end on Spring. It doesn't belong to the JDK (for sake thing you rejected Guava), there are lots of other DI frameworks in java.

Not to mention, in the java community, Spring has its share of criticisms for abuse of annotations and performance impact it creates.

Collapse
siy profile image
Sergiy Yevtushenko

I'm pretty sure that most of your bad feelings and experience with Java are coming from Spring framework. At the moment of its invention it was a great step forward, but over the years it get bloated, slow, poorly designed and even worse implemented memory hog. It overuses annotations and run-time reflection, enforces bad practices (business level exceptions probably one of the most prominent examples).
As a seasoned Java developer I saw a lot of different projects with wide variety of technologies. And Spring-based ones is a separate category of worst ones in regard to development experience. For last few years I'm not considering jobs which have Spring in job description and clearing this question with HR during screening.
So, my sincere condolences that you started your Java experience with such a project. After all, despite all critics, Java is great language with its own philosophy and for last few years it quickly evolves (and in right direction, as for me).

Collapse
davidsackstein profile image
david-sackstein Author

Please don't be cynical. TDD does not replace design, refactoring is always needed and this post is not about TDD.

davidsackstein profile image
david-sackstein Author
  1. System design is not old fashioned.
  2. TDD is not synonymous with "hack things about"

I really have no intention of discussing TDD here, but maybe you should do some reading up on the subject too.

Collapse
maherkh47239937 profile image
Maher Khalil

what about Rust?