Got Stuck? Most Difficult Parts of Learning Java and How to Overcome Them

Published in the Random group
As you know, we recommend coding beginners to start learning programming languages with Java, and CodeGym has everything to make the process of learning Java digestible even for the most unprepared students. But as much as gamification elements, easy-going story and funny characters help to ease this process, learning the fundamentals of Java in its fullest rarely goes without challenges for the majority of new learners. Got stuck? Most Difficult Parts of Learning Java and How to Overcome Them - 1Today we are going to take a look at some of the toughest areas in Java programming fundamentals, trying to understand why many people find them difficult and if there is something for you to do about it.

1. Generics

Generics in Java are types that have a parameter. When creating a generic type, you specify not only a type, but also the data type that it will work with. Generics are often mentioned by Java learners as one of the most difficult parts of Java for them to understand. “My main issue is still dealing with Generics. It’s much easier when you have methods with parameters to follow, but gets confusing when you’ve got to write your own,” said an anonymous Java learner.

Tips and recommendations

Here’s an opinion about Generics in Java from Ravi Reddy, an experienced programmer and university professor: “Java Generics do one thing that C++ templates do not do — implement type safety. The implementation of C++ templates is a simple pre-processor trick and does not ensure type safety. Generics in Java are like C++ templates but with additional type safety. And IMHO, type safety is an essential feature of any good development environment. And yes! They can be confusing because of our mental shifts between the parameters and the types. But I believe that spending time to master them is worth the effort. Because I found myself "thinking" much better in Java once I had understood interfaces and Generics."

2. Multithreading

Multithreading in Java is a process of executing two or more threads concurrently to achieve maximum utilization of CPU by the application. Multithreading solves very important tasks and can make our programs faster. Often many times faster. But it is considered to be one of the topics where many fresh Java learners tend to get stuck on. All because multithreading can also create problems instead of solving them. There are two specific problems that multithreading can create: deadlock and race conditions. Deadlock is a situation where multiple threads are waiting for resources held by each other, and none of them can continue to run. A race condition is a design error in a multithreaded system or application, where the operation of the system or application depends on the order in which parts of the code are executed.

Tips and recommendations

Here’s a good recommendation on how to deal with multithreading from S.Lott, a software architect and active user of StackExchange, a popular Q&A website: “Multi-threading is simple. Coding an application for multi-threading is very, very easy. There's a simple trick, and this is to use a well-designed message queue (do not roll your own) to pass data among threads. The hard part is trying to have multiple threads magically update a shared object in some way. That's when it gets error-prone because folks don't pay attention to the race conditions that are present. Many folks don't use message queues and try to update shared objects and create problems for themselves. What becomes difficult is designing an algorithm that works well when passing data among several queues. That's difficult. But the mechanics of co-existing threads (via shared queues) is easy.”

3. Classpath issues

Classpath errors are also considered to be one of the most complained problems Java developers are facing in their daily work. “Classpath problems can be time-consuming to debug and tend to happen at the worst possible times and places: before releases, and often in environments where there is little to no access by the development team. They can also happen at the IDE level and become a source of reduced productivity,” says Vasco Ferreira, an experienced Java/Javascript developer and programming-related tutorials author.

Tips and recommendations

“Classpath problems are not that low level or unapproachable as they might seem at first. It's all about zip files (jars) being present / not being present in certain directories, how to find those directories, and how to debug the classpath in environments with limited access. By knowing a limited set of concepts such as Class Loaders, the Class Loader Chain and Parent First / Parent Last modes, these problems can be tackled effectively,” explains the expert.

4. Polymorphism and using it correctly

When it comes to principles of OOP, many people say they had a difficult time understanding polymorphism. Polymorphism is a program's ability to treat objects with the same interface in the same way, without information about the object's specific type. Despite Polymorphism is quite a basic topic, it is rather extensive and forms a good portion of Java’s foundation. For many students, polymorphism is a first difficulty in learning Java. All because there are different forms of polymorphism used in different contexts, which can be confusing.

Tips and recommendations

There is no other way to deal with polymorphism other than learning it. Here’s how Torben Mogensen, who teaches programming at The University of Copenhagen, explains this concept: “Simple overloading: + can mean both integer addition, floating point addition and (in some languages) string concatenation. Subtype polymorphism: If B is a subtype of (inherits from) A, any value of type B can be used in a context that expects a value of type A. Parametric polymorphism: A type can be parameterised with type parameters, such that you in different contexts can supply different type arguments, so you instantiate the parameterised type to different concrete types. This is also called “templates” or “generics” and is in OO languages typically specified using angle brackets (such as T<A>). Interface polymorphism. This is basically a mechanism where you restrict subtype polymorphism to subtypes that implement a certain interface or parametric polymorphism to type parameters that implement a certain interface.”

5. Reflection

Reflection is a mechanism to explore data about a program while it is running. Reflection lets you explore information about fields, methods, and class constructors. It also allows you to work with types that weren't present at compile time, but which became available during run time. Reflection and a logically consistent model for issuing error information make it possible to create correct dynamic code. But for many people, it is not so easy to figure how to use Reflection.

Tips and recommendations

“In case of reflection and Java, reflection allows Java, which is designed to be statically typed, to be dynamically typed. Dynamic typing isn't inherently evil. Yes, it allows the programmer to break certain OOP principles, but at the same time it allows many powerful features like runtime proxying and dependency injection. Yes, Java lets you shoot yourself in the foot using reflection. However, you have to very explicitly point the gun at your foot, take the safety off and pull the trigger,” explains Jayesh Lalwani, an experienced Java programmer and application architect.

6. Input/Output streams

Streams let you work with any data source: the Internet, your computer's file system, or something else. Streams are a universal tool. They allow a program to receive data from anywhere (input streams) and send it anywhere (output streams). Their task is the same: to take data from one place and send it to another. There are two types of streams: input streams (used to receive data) and output streams (for sending data). What makes it difficult for many people to understand using streams is the fact that Java has multiple I/O stream classes.

Tips and recommendations

“Java has so many I/O stream classes mainly due to two contributing factors. First is legacy. Some classes are still there for historical reasons and they are not deprecated since they are not considered harmful. Second, flexibility. Different applications have different requirements and thus, you have multiple options depending on your requirements. Useful abstractions bring clarity when you read it and with few lines of code you can do a lot,” says Jonas Mellin, a Java expert from Sweden. What aspects of Java did you find the most difficult to understand or were stuck on for some time? Share your experiences in the comments.
What else to read:
Got Stuck? Most Difficult Parts of Learning Java and How to Overcome Them - 2
Comments (2)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Ibrahim Level 40, Sheffield, United Kingdom
19 February 2022
The best advice I can give others after having gone through more than half of codegym's course is that these things become clearer over time. In the beginning they are difficult to understood but if you're patient and persevere then you will find yourself finally understanding later on. The main thing is don't give up.
FrogTea Level 20
12 February 2022
Testing with JUnit, respectively Test Driven Development in general. Get used to debugging and testing your code with "proper" tools (e.g. testing frameworks) instead of trying to search for inconsistency "manually" line for line ... Especially for beginner a hard to achieve habit.