A better list for this discussion is amber-dev.

Regards,
Paul

On 5/26/26, 8:28 PM, "[email protected] <mailto:[email protected]>" <[email protected] 
<mailto:[email protected]>> wrote:

Hi all,
I am a long‑term Java application developer. I would like to share my intuitive 
thinking about null design from a pure object‑oriented programming perspective.
From my understanding of OOP, once a variable is declared as a certain type, it 
should always represent a valid instance of that type.
However, in current Java, when I declare an object variable without immediately 
constructing a valid instance, it is assigned null by default. In my opinion, 
null does not belong to this type at all; it is an external state outside the 
entire object system. This is the root cause of NullPointerException and 
numerous redundant null checks, which goes against natural OOP intuition.
Meanwhile, I really dislike nullable type syntax such as Type?. It artificially 
splits a single type into two contradictory states, which only confuses code 
logic and increases developers’ mental burden.
My simple expectation for Java is as follows:
Instead of assigning an irrelevant null to an uninitialized object field, the 
language should provide a built‑in none instance that strictly belongs to the 
target type.
This none instance should satisfy the following conditions:1


1.
It is exactly an instance of the type itself
2.
It is a valid object so all methods can be called safely
3.
It supports natural chaining and automatic short‑circuit when empty


Such a design not only returns to the essence of OOP, but also fits naturally 
with current streaming and functional programming styles, resulting in cleaner 
and more consistent code.
Here are practical examples from daily development to illustrate my idea 
clearly:
Current cumbersome Java code (null checks are mandatory to avoid NPE)


// Declared only, default value is null
User user;


// Direct call will throw NPE
String username = user.getName();


// Verbose defensive null check
String username = "";
if (user != null) {
username = user.getName();
}


// Awkward Optional wrapping
Optional<User> optUser = Optional.ofNullable(user);
String username = optUser.map(User::getName).orElse("");
optUser.ifPresent(System.out::println);


// Return null when no matching data found
public User findUser(Long id) {
return null;
}




My ideal natural style with built‑in none instance


// Uninitialized, default is the native none instance of User, not null
User user;


// Safe direct call with no exception
String username = user.getName();


// Native fluent chaining with automatic short‑circuit
String username = user.map(User::getName).orElse("");


// Execute logic only when a valid instance exists
user.ifPresent(System.out::println);


// Check for native none instance
if (user.isNone()) {
// Business logic for uninitialized state
}


// Return type-owned none instance instead of null
public User findUser(Long id) {
return User.None;
}




Confusing Type? design (type splitting leads to high mental load)


// One single type is split into User and User?
User? user = null;


// Constantly need to handle nullable differences
String username = user?.getName();


// Developers always struggle to judge whether it is a valid object
// Essentially still dealing with non‑object null state, not real OOP




To sum up:
In object‑oriented design, the empty state of a type should still be an 
instance of that type, rather than a meaningless null pointer or a confusing 
split‑type syntax.
This is only my personal experience and intuitive design idea as an application 
developer. I do not discuss any underlying implementation details. I look 
forward to community discussion and feedback.
Best regards
A Java Backend Developer





Reply via email to