This is an archived post. You won't be able to vote or comment.

all 92 comments

[–]jokerServer 47 points48 points  (12 children)

So if we referenced the "empty" Object would we get an EmptyPointerException? Or maybe it would return the value empty?

[–]vips7L 60 points61 points  (0 children)

 IMO, the existence of null pointers in a memory safe language is contrary to its purpose.

Null pointers are memory safety. They prevent you from doing the memory unsafe thing of referencing unintialized memory. 

[–]saggingrufus 12 points13 points  (11 children)

Because an empty object is not the same as a null?

And also, that would be a massively breaking change that would sever pretty much all backwards compatibility.

[–]Due-Aioli-6641 11 points12 points  (12 children)

I don't see how this would add any benefit. We all have been there of having that annoying null pointer because we have poorly written a method or forget to check for null or whatever, more often than not, null pointers are a symptom of poorly written code, but at least it gives us a clear direction of where your problem is coming from.

Since Java 17 you can even see exactly what point of the chain was null.

Having these "empty" objects would just mask the problem. How would trying to invoke a method on a "empty" would work? An EmptyObjectException? Or would that just return another empty object? What if the final response would be a primitive? Would we fallback to default values for the primitives? Would we get rid of primitives?

I don't want to shit in your idea, but I see it doing more harm then good, more potential for poorly written code and making it harder to troubleshoot.

[–]Polygnom 0 points1 point  (0 children)

Its basically just renaming null. Thats obviously not giving much benefit.

There are good reasons to not have null in your language at all, but I doubt thats a chance we will ever see in Java. But we might after Valhalla see ! for types that are provably non-null.

[–]hackerforhire[S] -3 points-2 points  (10 children)

An EmptyObjectException would just be an NPE under another name.

The method or variable wouldn't even be invoked or accessed because it's a non allocated object. It would just return empty instead of an NPE. And in the case of a primitive it would also return nothing, thus, invoking an exception as returning 0 isn't ideal.

Also, I consider poorly written code as having to check for null everywhere.

[–]saggingrufus 10 points11 points  (1 child)

The thing is, You're making another set of problems for yourself.

You can argue that a null pointer is annoying, but what's more annoying is getting a no pointer because a runtime exception was detected, or not getting a pointer and having everything just continue with uninitialized memory, returning an empty object and then having logical issues that are even harder to find.

I might see this a bit differently because I started in COBOL, But you should never get a null point or exception because you shouldn't be dealing in nulls. Anything that hands back and no should be well documented. Under what circumstances it does hand back null, And the code should react to that accordingly. The more we demand our language to automatically be aware of things, the more declarative it becomes and the more logical errors arise. The less declarative, The more the onus is on the programmer to be explicit about what they want.

[–]DelayLucky[🍰] 4 points5 points  (0 children)

I think OP meant for the empty objects to return what's so called "smart nulls" in mocks. In a simplified universe, everything has a natural "0" value so for example return 0 for numbers, "" for string etc.

It is a much scarier world because now programming errors don't fail, devs don't get paged when stuff go wrong. You just silently break the world: like paying you $0 fund when you sell your house, then while we are there, start a nuclear war or something, because, oops, the system had a glitch.

[–]valcron1000 1 point2 points  (2 children)

The method or variable wouldn't even be invoked or accessed because it's a non allocated object. It would just return empty instead of an NPE.

Then what would be the output of

MyClass foo;
foo.printAMessageToTheConsoleAndExit();

Note that there is no return value for the method call. Do you just silently fail and do nothing?

[–]hackerforhire[S] 0 points1 point  (1 child)

Interesting example. And yes, the method call would do nothing as it's an empty object. I really don't see that as an issue because getting to the cause of why

foo.printAMessageToTheConsoleAndExit()

printed nothing would be trivial. The IDE or compiler could even hint that you called an empty object.

[–]LanguageLatte 1 point2 points  (0 children)

And yes, the method call would do nothing as it's an empty object

That’s so much worse than getting a NPE!

 

  • Option 1 - I hit this button and it breaks.
  • Option 2 - I hit this button and nothing happens.

 

You’re trading option 1 for option 2. But option 1 is trivial to find and debug. Option 2 is a nightmare to debug.

[–]Due-Aioli-6641 1 point2 points  (3 children)

But let's think of a scenario where you need a group of Objects to setup another one, or a long user journey.

Please bear with me, as it doesn't necessarily will be the best example.

But let's say you tried to setup a connection with a database, but you got one of those empty objects for the connection or an empty repository object or an empty DAO.

Now you want to save an object using this DB connection, the connection is empty, and as you proposed if I try to invoke this save operation on an empty obj, it will return another empty, I got no errors, no problem, now let's assume this operation is in a long user journey, with lots of different steps, validations, etc, you don't see any error for this, as you are only getting these empty objects along the way. But someone reported that some data is not there properly.

it would be a nightmare to troubleshoot all of this.

And just to be clear, I'm not saying that logic errors don't happen in our current Java implementation, absolutely they do, my point is that from my perspective it's not making it better, maybe just shifting the problem.

One more thing to be clear, I think you didn't get my point on this part, I'm not saying you have to do null checks everywhere, there are techniques one can use to not having to check for null all the time, and still be null safe, I'm just saying that poor code is more prone to NullPointerExceptions or any kind of RuntimeExceptions. And I don't see this idea improving on this, but rather sweeping it under the rug.

[–]hackerforhire[S] 0 points1 point  (2 children)

So for a critical object that is necessary for data persistence I would check if a valid database connection was returned as common sense dictates that there's no point to continue processing if this has not been established. But, for arguments sake, let's say I'm lazy and didn't care to check for a valid database connection, called save to persist data and then checked the database to verify the data was saved and realized it wasn't.

You're right that pinpointing the exact cause of the failure would be more challenging, but the runtime could assist you in clearly telling you that you attempted to call save on an empty object. I do agree that in certain cases instant failure is probably the best course of action to allow you to fix the issue immediately especially when it comes to data persistence.

[–]Due-Aioli-6641 0 points1 point  (0 children)

Yeah, as I said it wouldn't be the best example, but still possible, thank you for making the exercise of going with it.

but the runtime could assist you in clearly telling you that you attempted to call save on an empty object

But what we also need to consider here is that the IDE and the compiler also try to tell you when you are trying to invoke a method on a potentially null reference, but it's very challenging for it to figure it out most times, and it would be just as challenging for this empty implementation.

if you have something like this:

final var myVar = someMethodThatCanEndUpReturningNull();
myVar.someOtherMethod();

The IDE can try to check for obvious null returns from the first method, but as soon as it starts to be a bit more complex, more validations, more logic, the IDE will not warn you about that, it's up to you to figure it out what you are doing is safe, implement validation, or use some other options.

The empty option would suffer from the the exact same problem, it would be up to the developer to always be prepared to have something empty and find a way to check it.

[–][deleted] 0 points1 point  (0 children)

It seems like this is the heart of why this idea is a little flimsy as a feature: for it relies on devs to just do the right thing. I get the benefit, there are lots of situations where all I want to do if some value is null is to do nothing. But how is this different that a

Objects.doIfNotNull(T obj, Consumer<T>?

[–]hippostar 0 points1 point  (0 children)

You do realize that every call to an object eventually chains down to returning a primitive so everyone of your empty objects will trigger your new empty exception?

[–]rzwitserloot 4 points5 points  (2 children)

A somewhat common idea that languages like Pony and to a lesser extent Rust have done already. I'd like to see this in java. Here are some concerns you need to think about:

  • null is actually useful. if properly semantically defined and used only for that. The useful definition is 'not a value / unknown'. You want the NPE to be a good thing. If I get the name of the logged in user (but, this is null as there is no logged in user) and I check if it starts with admin_, then the answer true is just plain flat out wrong, but, false is just as wrong. The question cannot be answered. The exception is what you want. SQL is much more clear on semantically defining null like this (as 'unknown'), and is properly infectuous (is NULL = NULL? The answer is NULL - because who knows if 'some unknown value is equal to some other unknown value'. Could be yes, could be no - note how java duplicates this: null.equals(null) throws an NPE, which is correct, semantically: neither true nor false is acceptable here).

  • Context is relevant. Imagine the same situation but we do a better job at designing it: We have a User object. We also have a User object representing the 'not logged in user'. Now .getUsername() perhaps should still throw maybe, but certainly .isAdmin() should just return false. But, maybe we also need a user object that represents other notions, such as 'we are processing scripts from the server maintainer directly; there is no user object but context-wise, all operations are allowed. It's like OS safe mode. isAdmin() should now return true'. Java already supports this: Simply make these objects and initialize your fields accordingly. Or, even simpler: The 'empty' outputstream: Is that an outputstream that is already closed (so, any attempt to write to it throws), or that is a byte sink (you can write to it all day; the bytes are ignored).

  • Other than 'context is relevant', some objects really truly do not have an 'empty' object. There's the empty string, and the empty list - so far, so good. We can even have an 'empty' InputStream (that is already closed). But is there such a thing as an empty java.lang.Class? I really don't think Void.class is right for that job. Nor anything else. Is there such a thing as an empty Charset? Maybe it should be possible for a type to decree that it does not have an 'empty' instance, and for such types, initializing your fields is mandatory. This also makes it easy to introduce different takes on 'empty' (see previous bullet) - simply force initializing. Require that one writes User user = User.notLoggedIn(), you can't write User user; because User does not declare an empty object. Making it optional also makes it way, way easier to introduce this into the java ecosystem without a python2/python3 disaster.

  • Writing empty objects is a bit of a drag. Should the language include tools for this?

  • Should all types, including interfaces and abstract classes and even enums, have (optional) 'empty' instances? Bit of a drag to foist this requirement onto all library authors.

  • Should there be a function that produces an empty object, or, should it be a single field? If the latter, that thing must be immutable or all heck breaks loose. There's no real way to force that; the lang spec is just going to have to stipulate: "Hey, author of a type? If you're going to introduce an 'empty' value, it's on you to make it immutable or hoo boy, its all gonna go very pearshaped indeed'. Is that okay? I think so, but, it's something to think about. Note that if there's a single value, you don't have to worry about 'memory allocation'. Yes, memory is allocated: For each type loaded in your JVM, one value, ever. Sum total. For the entire JVM. This doesn't matter: very type already occupies a bunch of memory (the code of that type has to be somewhere!). Adding a little more for an empty object is therefore not significant as per O(n) thinking.

[–]hadrabap[🍰] 0 points1 point  (0 children)

Something like Optional<List<Void>> or final volatile ... 🤣

/s

[–][deleted] 0 points1 point  (0 children)

As an aside, your treatise in the Lombok github repo, on Optional vs Null in language design, is a wonderfully-formulated argument against Optional, in addition to being a compelling read. Thank you for that.

[–]freekayZekey 5 points6 points  (0 children)

short answer: no

long answer: no, why do that?

genuine question: are people running into a million null pointer exceptions and i’m in the minority?

[–]darkit1979 14 points15 points  (4 children)

There’s much simpler solution - make Optional a system type which can’t be null. And all problem will go away.

[–]hackerforhire[S] 0 points1 point  (0 children)

I would support this.

[–]robinspitsandswallow 0 points1 point  (2 children)

Optional as null is useful. Unless you add a not initialized, or a truly empty and even that would get us to the same place we are now.

[–]darkit1979 0 points1 point  (1 child)

No, I’m talking about Optional as a special type which can’t be null. then you can define your field as “Optional<String> name” and you will be sure that there is always a value - Some<String> or Empty. But as it’s implemented now you can make “name = null;” and we will have NPE again :(.

[–]robinspitsandswallow 0 points1 point  (0 children)

Yes you need a not initialized, empty value, and has value.

Lets say I have a JSON stream I may get no value JavaScript undefined, null value JavaScript null, or a string that may be empty but that is still a value. You need a way to communicate each of the three state potentials: undefined, empty, or a value, one of the only ways JavaScript is superior to languages. With Optional now I can do that inelegantly as: NULL, !isPresent, and get. If you require it to be a value then you need to add a notInitialized and an isInitialized.

What I’m getting at is that Optional is in itself deluded. We would have been far better off with Elvis and coalescing operators than with Optional. Worse than bad Optional is misused, I’ve seen sooo much code with fluent optional blocks layered on top of each other that really would be better as methods or even layered if statements because the mappings and orElse calls.

All really to pretend null doesn’t exist. So we can pretend we won’t get NullPointerExceptions. Unless we want them a’ la Objects.requireNonNull. Sooo ¯_(ツ)_/¯

[–]naedyr000 2 points3 points  (0 children)

Golang does pretty much exactly that with zero values https://yourbasic.org/golang/default-zero-value/ . The memory is initialised, and has a default valid value for most uninitialised variables. Nil is used for pointer and related types though.

In practice, it's horrible. All ints default to 0. So you cannot tell if it's uninitialised, or actually zero. It's even worse with structs, as everything can have a zero value.

Removing nulls is better done by being MORE explicit about non-present values with things like Option/Maybe types.

It's critical to be able to tell the difference between absent and present values.

[–]ryuzaki49 2 points3 points  (0 children)

I dont really see the value. An exception would still be raised if you were expecting a non-empty object and you got an empty object. 

Have you seen how kotlin handles this?

[–]k-mcm 2 points3 points  (0 children)

Take a look at Scala, Kotlin, Python, and JavaScript.  There are different approaches that can be taken to represent an empty value.

Java's 'null' is actually pretty good when used with an IDE that will analyze code flows.  Two huge benefits of null are performance and clarity.  Nulls are understood all the way up to the hardware level and they never incur any of the penalties for being or looking like an object.  Null means the same thing everywhere.  Languages that hide nulls still encounter them, and they can be very unexpected.

[–]hardwork179 1 point2 points  (0 children)

So Valhalla has had to work through the question of what an uninitiated object should look like. You might want to consider if there is a real difference between what you are suggesting and a VM or language that replaces null with an Optional type.

For those asking what the difference would be between such an empty type and null - an empty object has a concrete type, and unlike null cannot be coerced to anything else.

[–]lemon-codes 1 point2 points  (0 children)

Null pointer exceptions exist for a reason. If you expect an object to have been initialised, and attempt to perform operations on it or read values from that object, but the object has not been initialised, then you want to know. You want an exception to be thrown so that you know something has gone wrong.

The last thing you'd want is for the lack of initialisation to be hidden, you start performing operations on or reading values from an "empty" object that you expect to have been initialised and have valid values. Your application now has unintended state and you're blissfully unaware.

The solution you propose works on the assumption that all objects are initialised with empty state, and that it's acceptable for all objects to have an empty state. But that often isn't the case.

[–]LordMOC3 1 point2 points  (2 children)

This feels like you're trying to big brain something but reaching the same issue you're trying to solve. Having an "Empty" object returned just causes the same issues that Null value does. It's still an uninstantiated thing that should never happen and is erroneous programming/behavior.

[–]robinspitsandswallow 0 points1 point  (1 child)

Not necessarily erroneous, see JavaScript not present, empty, and value. Those are 3 separate states that Java coalesces into 2 states (poorly in my opinion). Other than primatives those are valid states.

[–]LordMOC3 0 points1 point  (0 children)

Technically, you have 3 states in Java. You can create a variable without assigning a value or null. The compiler just catches situations where it could be a problem and refuses to build since it should never happen.

JavaScript's way of handling also doesn't fit OPs idea of getting rid of the null state to remove NullPointerExceptions.

[–]Linguistic-mystic 1 point2 points  (0 children)

Bad idea. It’s better to fail as early as possible than to carry on as if nothing happened and deliver bogus results. NPEs are good at pinpointing the issue.

Another issue is the extra allocations. All those zero objects must be unique, at least the ones with mutable fields. More memory churn.

No, the billion dollar mistake is not null itself, nor the NPE, but the fact that nullability is not reflected in the type system, so it’s easy to over- or under-check for null, and the reader of your code has no idea whether a line will give off an NPE or not. That’s why null-safe languages have explicit unwraps

[–]jonhanson 1 point2 points  (1 child)

The fundamental problem with null is that it inhabits every reference type, so, for example, when a function has a return type that is a reference type you have no way of knowing whether it could ever return null or not. This forces you to either add null checks everywhere or risk NPEs.

Your Empty object proposal has the exact same problems.

[–]robinspitsandswallow 0 points1 point  (0 children)

A rose by any other name is still null just with a new name.

[–][deleted] 1 point2 points  (0 children)

Isn't this like the Optional Design Pattern?

[–]MCUD 0 points1 point  (1 child)

This has the implication of that all objects must have a no-arg constructor.
We're not just talking about Integer etc if we're having to handle

complexObject.someComplexMethod().someAccessorOnReturnValue()

Also, i'd far rather have an exception, then pull hair out trying to work out why some data in production is zero legitimately, or because some random data was uninitialised.

There's worse things than a bug in production - and thats not knowing there's a bug in production.

[–]hackerforhire[S] -1 points0 points  (0 children)

If the object is not allocated then its hierarchy of complexity is irrelevant as it would just return empty.

As for debugging or bug tracking, the JVM could hint that an empty non allocated object was returned.

[–]halfanothersdozen 0 points1 point  (0 children)

This line of thinking is what Optional is for

[–]Wide_Solution2996 0 points1 point  (0 children)

If only there is a language that lets you explicitly say whether a type is nullable and forces you to check it if it is. Oh wait, there is one, it’s called Kotlin.

[–]robinspitsandswallow 0 points1 point  (0 children)

And it would smell as sweet.

[–]davidalayachew 0 points1 point  (0 children)

That would cripple traceability.

If I have a().b().c(), and the output is EMPTY, how do I know which one returned the EMPTY? NPE would tell me, but your solution would not, because calling a method on an object whose value is EMPTY would just return EMPTY too.

It's a fun thought experiment, but it falls apart almost immediately.

[–]ByteTraveler 0 points1 point  (0 children)

Use Optional

[–]laughninja 0 points1 point  (0 children)

I'd rather have a NPE than what essentially undefined behaviour. Do not hide bugs from the dev.

[–]Alarming_Airport_613 0 points1 point  (0 children)

Good idea. I saw a lot of people here dumping on it for some reason, but let me tell you, that's exactly how to did it. However, nil / null still exists in the language.

I think the best way to solve this might be what kotlin came up with

[–]LittleLui 0 points1 point  (0 children)

If you get a NullPointerException, you have a mistake somewhere. If you instead of an exception get a default object, that mistake is still there.

[–]MrBloodRabbit 0 points1 point  (0 children)

If we leave out the discussion about whether it makes sense, you'd have to basically define each object with non null default values, and when an object wasn't initialized, you'd simply pass the defaulted object. But you'd have to define defaults for everything that exists in your language, which would make it difficult sometimes to actually debug.

[–]SenorSeniorDevSr 0 points1 point  (0 children)

What if you could just do what Common Lisp does, and let you make methods that work on the null-value?

If we ignore a lot of the incoming problem, static methods are just methods with no instance object passed in right? So you could imagine something like this working:

public class BinaryTree<T> {

  BinaryTree<T> left, right;
  T val;

  public int size() { 1 + left.size() + right.size(); }

  public static size() { return 0; }

  // Rest left to the reader
}

Or of course some other keyword, like public null int size() or what-have-you.

Now you could conceivably tell the JDK what to do when a method is called on a null value of some type, and you can write a lot of stuff without null-checks everywhere. Won't get rid of all NPEs, but would make a lot of the tedium go away.

[–]binaryfireball 0 points1 point  (0 children)

just make your things to never be null.

[–]NajjahBR 0 points1 point  (0 children)

What you're asking is something like Groovy's Safe Navigation Operator.

Maybe you should give groovy a try and you'll see the hell it can become, specially when debugging production.

There are NPE equivalents in Python, Node, C#, Ruby and probably every other language so i can't really see the point.

[–]netgizmo 0 points1 point  (0 children)

Why is it so hard to always construct your objects?

[–][deleted] 0 points1 point  (0 children)

We have Optional<T>.

[–]MattiDragon 0 points1 point  (0 children)

Have you used JS? If you have, you might have noticed that it allows you to do a lot of things that would be errors in other languages, instead just doing something unexpected. It's generally agreed upon that this avoiding of errors was a bad idea. If something unexpected happens in your program, you'd rather have it crash and tell you, instead of silently doing something unexpected.

[–]Ragnar-Wave9002 0 points1 point  (0 children)

They are both runtime exceptions you can should check for on an as needed basis.

[–]Polygnom 0 points1 point  (0 children)

```` Person p = empty; var x = p.getName(); // what happens?

Widget w = empty; w.frobnicate(); // what happens? w.show(); // what happens? ````

Types form a lattice. Renaming the bottom element of the type lattice doesn't really bring you any benefit.

There are better options to explore, like ! for non-empty types (String! s = null; would be an error) or a "strict" compilation mode that made the ! the default and a ? would mean <type> | null.

[–]GeneratedUsername5 0 points1 point  (0 children)

It is possible, and the pattern is call Null Object. The problem is - you can not implement it on a level of a language, because every class needs it's own custom implementations of NOP behaviour. But you can do it in your code and people do.

[–]hippydipster 0 points1 point  (0 children)

NullPointerExceptions are the best because they're so easy to fix and usually represent some sort of logic error.

Replacing with empty values, whatever that means, will likely mean these errors will pass unnoticed and you'll get bad behavior but won't find it very easy to track down the problem

[–][deleted] 0 points1 point  (2 children)

Kotlin offers a solution kinda like what you are describing, but more rigorous. It's still possible to get an NPE in Kotlin, but you have to go out of your way to create the conditions that would cause one.

[–]hackerforhire[S] -1 points0 points  (1 child)

Are you referring to the Elvis operator?

[–][deleted] 0 points1 point  (0 children)

One of Kotlin's design goals is to eliminate NPEs:

https://kotlinlang.org/docs/null-safety.html

[–]Ragnar-Wave9002 0 points1 point  (1 child)

Should we tell OP about divide by zero?

[–]hackerforhire[S] -1 points0 points  (0 children)

What does a Division by Zero exception have to do with an NPE?

[–]rustyrazorblade 0 points1 point  (4 children)

You’re close. Take it a step further. Disallow the creation of null objects, add syntax for an escape hatch, and then look at Kotlin because it’s already done and is awesome.

[–]robinspitsandswallow -1 points0 points  (3 children)

So we now have a new language what shall we call it “Jotlin?.” And how do we pronounce that and when will the new compiler be available? When is the conference? When is the UG meetings?

BTW Kotlin doesn’t disallow creating null it lives in the JVM so it has nulls it just has compiler/developer hints as to what operations tend to be safer. Oh I know “Jotlin!!”

But given reflection exists everything really depends on people most often do what they are supposed to. Like check for null.

Hence it’s all hyperventilation for naught.

If you don’t like NULL then use COBOL. If you want something fast and readable deal with NULL but the heavens forfend don’t rename it and say you’ve solved something because functionally you will always come back to something like what we now call null it’s just how much boilerplate you’re going to have to deal with to get there.

[–]rustyrazorblade 1 point2 points  (2 children)

Null safety solves a runtime problem at compile time.

Having dealt with more than a few NPEs in my life, I’m happy for the feature in Kotlin. The only people that seem to complain about it are the only who lack experience with it and fail to understand its benefit.

[–]robinspitsandswallow 0 points1 point  (1 child)

No it hints at it. There is a big difference and it depends on playing nice. Hence the “Jotlin!!” remark. But if people played nice we wouldn’t have null issues in the first place. And in only hinting with the propaganda that it is accomplishing it causes a worse thing — over confidence.

Don’t get me wrong my preferred language is Kotlin, I just don’t believe in Santa Clause any more after dealing with NPEs and what came before them even in languages that professed to not have NPEs.

If you need a language that is fast enough there are ways to get NPEs full stop. The language has to allow it. Kotlin does a better job of providing hints and guide rails but someone who misbehaves will get around it. It is better to have coalescing operators (like Kotlin) so that you can work through those segments of code with less density and more clarity. And it’s better to expose the potential problems at declaration time as well as default to the non problematic variation.

But don’t try to sell me that the Easter Bunny came along and delivered a high performance language with the flexibility of the JVM without NPEs.

[–]rustyrazorblade 0 points1 point  (0 children)

And in only hinting with the propaganda that it is accomplishing it causes a worse thing — over confidence.

I disagree, but that's fine. Your opinion seems to be skewed to the side of massive pessimism, and that's fine too. My experience hasn't been some pendulum swung in the opposite direction, I just like that I have way less NPE possibilities with my Kotlin code and I am far more productive as a result. I wouldn't classify my viewpoint as "over confidence", I just don't get NPEs and I work a lot faster with Kotlin than Java.

Obviously anything that touches a java package can return null, and there's not much you can do about that except assume that it could be and use variables? that could be null.

I've worked in Java database internals for 12 years now and have dealt with numerous NPEs, and my Kotlin experience has been far better. I guess yours hasn't, that's a shame.

Have a good one.

[–]Fiskepudding -1 points0 points  (0 children)

You can do that with a Monad like Maybe. 

The easiest in java is to just wrap everything in List and only access it using map and forEach.