Question 1
Difficulty: medium
Can you walk me through how you would design a RESTful API in Java for a customer management system?
Sample answer
When I design a RESTful API, I start by clarifying the business actions the system needs to support, then I map those to resources and HTTP methods. For a customer management system, I would define endpoints like /customers, /customers/{id}, and maybe /customers/{id}/orders if that relationship matters. I’d use standard HTTP verbs, clear status codes, and consistent request and response formats, usually JSON. I also think early about validation, pagination, filtering, and error handling so the API stays usable as it grows. In Java, I’d typically use Spring Boot because it gives me a clean structure, dependency injection, and easy integration with validation and security. I’d also document the API with OpenAPI so front-end and QA teams can work efficiently. Beyond the basics, I pay attention to idempotency, versioning, and logging, because those details make the API maintainable in real production use, not just in a demo.
Question 2
Difficulty: hard
How do you handle concurrency issues in Java, especially when multiple threads update shared data?
Sample answer
I treat concurrency as a design problem first, not just a code problem. If multiple threads need to update shared data, I try to reduce shared mutable state wherever possible because that is the cleanest way to avoid bugs. If sharing is necessary, I choose the right tool based on the use case. For simple counters or flags, I might use AtomicInteger or volatile. If I need coordinated access to a block of code, I’d use synchronized or a ReentrantLock, but only when necessary because locking can affect performance and readability. In more complex services, I also look at concurrent collections like ConcurrentHashMap or use thread-safe queues for producer-consumer patterns. I’ve found that race conditions often show up only under load, so I like to test with concurrency-focused scenarios, not just unit tests. Good logging and metrics also help trace timing-related issues in production if something unexpected happens.
Question 3
Difficulty: hard
Tell me about a time you had to debug a difficult production issue in a Java application.
Sample answer
In one project, we had an intermittent timeout issue in a Java service that only appeared during peak traffic. The tricky part was that it looked like a database problem at first, but the root cause was actually connection pool exhaustion caused by a slow external API call in the same request flow. I started by checking logs, thread dumps, and application metrics to understand where requests were stalling. Then I traced the slow path and found that some requests were waiting too long for the external service, which caused threads to pile up and starve the pool. I helped the team separate that integration into a more resilient flow and added timeouts, circuit breaking, and better fallback behavior. We also improved monitoring so we could see the issue earlier next time. What I took from that experience is that good debugging is about forming and testing hypotheses quickly instead of guessing based on the first symptom you see.
Question 4
Difficulty: medium
How do you approach writing clean, maintainable Java code when working in a team?
Sample answer
I try to write code that another developer can understand quickly without needing a long explanation. That starts with keeping methods small and focused on one responsibility, using meaningful names, and avoiding unnecessary cleverness. I also like to separate concerns clearly, especially in Java applications where business logic, persistence, and API layers can get mixed together if you are not careful. On a team, consistency matters, so I pay attention to shared conventions for formatting, exception handling, and package structure. I also think code reviews are a major part of maintainability because they catch design issues early and help the team align on standards. When I review code, I look beyond whether it works and ask whether it will be easy to test, extend, and debug later. In my experience, maintainable code is less about perfect architecture and more about making good choices repeatedly so the system stays understandable as it grows.
Question 5
Difficulty: easy
What is the difference between an interface and an abstract class in Java, and when would you use each?
Sample answer
I think of interfaces as a way to define a contract, while abstract classes are better when I want to share some common behavior or state across related classes. An interface is useful when different classes can share the same capability even if they are unrelated in the class hierarchy. For example, multiple payment processors might implement the same interface even if their internal logic is very different. An abstract class is a better fit when I have common fields, helper methods, or partial implementation that several subclasses should reuse. I usually prefer interfaces when possible because they keep the design flexible and make it easier to swap implementations or support multiple behaviors. But I do not force everything into interfaces just for style. If a shared base class reduces duplication and makes the model clearer, an abstract class is the right choice. The main thing is to choose the structure that keeps the code easy to evolve.
Question 6
Difficulty: medium
How do you ensure your Java applications are secure, especially when dealing with user input and authentication?
Sample answer
Security starts with assuming that all external input is untrusted. For user input, I validate and sanitize data at the boundary, both on the API layer and again where needed in the business logic. I avoid building SQL queries by concatenating strings and use parameterized queries or ORM features to reduce injection risk. For authentication and authorization, I rely on established frameworks rather than custom logic, and I make sure roles and permissions are checked at the right layer. I also pay attention to password handling, which means never storing plain text passwords and using strong hashing algorithms with salt. On the application side, I look at session management, token expiration, secure headers, and HTTPS. Logging is another area I handle carefully because sensitive data should not end up in logs. In practice, secure coding is about consistent habits, not one big safeguard. If the team builds security into everyday development, the risk drops significantly.
Question 7
Difficulty: hard
How do you optimize the performance of a slow Java application?
Sample answer
I usually approach performance issues systematically instead of guessing. First, I identify where the slowdown really is by checking metrics, logs, and profiling data. Sometimes the issue is in the JVM, but often it is actually in database calls, network latency, or inefficient business logic. If the application is CPU-heavy, I use a profiler to find expensive methods, excessive object creation, or unnecessary loops. If it is memory-related, I look at heap usage, garbage collection behavior, and possible leaks. I also review database access patterns because an N+1 query problem or missing index can make a Java application feel slow even when the code itself looks fine. Caching can help, but only if it is applied carefully and with clear invalidation rules. I also check whether concurrency is being used effectively, because too many threads can hurt performance just as much as too few. My goal is always to measure first, change one thing at a time, and verify the improvement.
Question 8
Difficulty: medium
Describe a situation where you had to learn a new Java framework or library quickly. How did you handle it?
Sample answer
I have had to pick up new frameworks several times, and I usually learn them by combining documentation, a small prototype, and practical use in the actual project. One time I needed to get productive quickly with a framework the team had already adopted, so I spent the first day understanding its core concepts, project structure, and common patterns instead of trying to learn everything at once. Then I built a simple proof of concept to see how dependency injection, configuration, and testing worked in practice. That helped me connect the theory to the team’s codebase much faster. I also asked targeted questions to teammates rather than broad ones, because specific questions tend to save everyone time. After that, I focused on one feature area and contributed there first, which helped me learn while still delivering value. My approach is to be intentional and practical: learn enough to be useful quickly, then deepen the knowledge as the project needs it.
Question 9
Difficulty: medium
How do you write unit tests for Java code, and what do you consider a good unit test?
Sample answer
A good unit test should verify one behavior clearly and fail for the right reason. I usually start by testing the business logic in isolation, mocking external dependencies like databases, APIs, or message brokers when needed. That keeps the test fast and focused. In Java, I often use JUnit and Mockito because they support readable, maintainable tests that fit well into a CI pipeline. I care about testing edge cases, not just the happy path, especially where null values, invalid input, or boundary conditions can cause defects later. I also try not to over-mock because tests can become brittle if they mirror the internal implementation too closely. The goal is to validate behavior, not lock in every detail of the code structure. When I look at a test suite, I want it to give the team confidence to change the code. If tests are slow, unclear, or hard to maintain, they stop being useful very quickly.
Question 10
Difficulty: hard
If you inherited a legacy Java codebase with poor structure and limited documentation, how would you improve it without risking major regressions?
Sample answer
I would improve it incrementally and keep risk low. My first step would be to understand the current behavior by running the application, reading the most important flows, and identifying the areas that change most often or cause the most defects. Before making major refactors, I would add tests around the existing behavior so we have a safety net. Then I would prioritize improvements that give the highest value with the least disruption, such as extracting duplicated code, clarifying naming, and separating business logic from infrastructure concerns. I would avoid large rewrites unless there was a very strong reason, because legacy systems usually carry a lot of hidden business rules. I also like to work in small pull requests so changes are easier to review and roll back if needed. Communication matters here too: I would keep stakeholders informed about what is being improved and why. The goal is steady reduction of technical debt while protecting the business from unnecessary risk.