#Null handling like in C#
1 messages · Page 1 of 1 (latest)
<@&987246399047479336> please have a look, thanks.
Here is an AI assisted attempt to answer your question 🤖. Maybe it helps! In any case, a human is on the way 👍. To continue talking to the AI, you can use </chatgpt:1108714622413963314>.
In Java, there is no built-in operator like the ? operator in C# for handling null values. However, you can use methods like Optional.ofNullable() or Objects.requireNonNullElse() to handle null values safely and prevent NullPointerExceptions. These methods allow you to provide default values or perform actions if a value is null.
Useful links:
you can wrap in an Optional and use a bunch of maps
but yeah for most things: just use ifs
var n = Optional.ofNullable(s)
.map(Thing::name)
.map(o -> o.length())
.orElse(null);
like this can work - sometimes
well there are actually two things here
there is:
But java has the best enums ever so I guess it cancels out
and also "non-null" strings (String!)
they are actively working on that
- "null chaining"
There is also shorter null checks
which might feel like an obvious feature, but there is more nuance than you'd expect
whatever the case: null types come first
my guess is that ?., ?:, etc. might not come ever or for a long time: they aren't as obvious as some people think
Like if you get a null reference exception in C# you are probably just using a ! To ignore everything cuz like
the main reason is that they make writing code easier - ?. is easier to type than a whole if ... == null) check
IT just doesn’t allow it rly
Exactly
but the downside is that it makes code harder to read
?. is a very small visual signal for an important branch in control flow
Not rly
Ive never had issues with that
just know the language designers are aware of all the features people want and are working on the first one
return {
statusCode: 200,
responseBody: {
id: organization_id,
displayName: result?.identity_organization_by_pk?.display_name,
profileImageUrl: result?.identity_organization_by_pk?.profile_image_url,
email: result?.identity_organization_by_pk?.mainEmail?.[0]?.value,
agency: result?.identity_organization_by_pk?.agency && {
displayName: result.identity_organization_by_pk.agency.display_name,
profileImageUrl:
result.identity_organization_by_pk.agency.profile_image_url,
},
lumanuId: result?.identity_organization_by_pk?.lumanuId?.[0]?.value,
},
};
consider this typescript
notice how the ?.s "fade into the background" when you read the code?
i'm not saying there aren't positives, but its not like it has no negatives
if you want nullable types in java today there is this
Standard Annotations for Java Static Analysis
its in the works but its complex
oh it is in the works?
bc its not just about adding it but adding it the right way
yes
if u follow recent talks by brian and friends ull see it being a topic
what about extension methods
those are great too
kotlin has them
so why java not yk
extension methods is one of the features that, if misused, results in terrible code
so it makes sense for an expert-lang like kotlin
but not for java
java will never get extension methods
similarly there are interviews with the language designers where they explain why
but tl;dr; is that extension methods are a net negative language feature
you are allowed to like them, but they also sit on the "make code harder to read, easier to write" side of things
(and are a baby version of a more powerful feature called implicits/type classes)
(I wrote about this here, but seek out the interviews with the language designers if you want to know why they don't want them)
true but at the end of the day writing code is more important than reading code. i see what yuo mean though
honestly its not even that hard to work around it but they are just nice to have
If you really need that many nulls, your data is probably badly mapped
Like, say you have an object you get from somewhere, the more modern approach is to have your accessors return Optional. If your way of getting said records does the same, you're basically just flatmapping optionals together, which is imho the proper approach.
Common wisdom is the opposite
Most time you spend developing is just reading and tweaking code
It’s a map.get
Fair ig
think of Java as a big compromise between everyone who wants different things
Show me some code, and I'll show you
map.get can return null. it sounds like they're trying to avoid that
they want an evlis operator system
its like a node structure i need one map.get then another .get etc.
if the first doesnt exist i get an NPE though
thats a composite structure, the composite pattern
that doesnt make any difference here
good news!
there is a better solution
they want to worry about null handling. Optional is basically the only option
first, this code is giving me a migrane. what are you trying to do?
and what is the data type here?
the solution is to approach it differently and not to try to keep the current structure @neat glacier
but for that one needs to understand the situation better
ye i know but idk how to change it
you need to understand im working with a mc codebase here so half the stuff i have to use are out of my control in the first place
but basically this
its a partdefinition with children of the same type
i need to get a head partdefinition
but it could be capitalized, it could be a child of a body, which could also be a child of root
but it depends on the model and i want to capture like 90% of cases
sounds like u have a graph and want to do graph exploration like bfs
okay lets write out these cases
you make it sound super hard
Head
head
body -> Head
body -> head
Body -> Head
Body -> head
root -> body -> Head
root -> body -> head
root -> Body -> Head
root -> Body -> head
Root -> body -> Head
Root -> body -> head
Root -> Body -> Head
Root -> Body -> head
are these all the options
yes
they are
it feels like binary counting or something
its weird
or like ternary
nah ig there are 2 states
okay so all we have is .getChild which either returns the child or null?
(permutation is the term ur looking for)
yep
its just a map#get call
what java version?
ok a few minutes
👍
always looking to improve so if there is a better way i would love it lmao
this isnt the first time encountering this type of problem
record Entry() {}
static class EntryMap {
Entry getEntry(String s) {
if (Math.random() < 0.1) {
return new Entry();
}
else {
return null;
}
}
}
void main() {
var m = new EntryMap();
var list = Arrays.stream("""
Head
head
body -> Head
body -> head
Body -> Head
Body -> head
root -> body -> Head
root -> body -> head
root -> Body -> Head
root -> Body -> head
Root -> body -> Head
Root -> body -> head
Root -> Body -> Head
Root -> Body -> head""".split("\n"))
.map(row -> row.split("->"))
.map(row -> Arrays.stream(row)
.map(String::strip)
.toList())
.toList();
IO.println(list);
for (var path : list) {
Entry e = null;
for (var entry : path) {
e = m.getEntry(entry);
if (e == null) {
break;
}
}
if (e != null) {
IO.println(path);
IO.println(e);
}
}
}
@quiet violet just ad-hoc
oh i never thought about doing it with a loop like that
ad hoc?
but i'm sure its less painful than what you have going
like the string.split code you wouldnt need and i didn't make it "real"
but i think you can see the idea
ye i can just make it a string array directly
wait how does this work
oh with an entrymap idk what that does
yeah wait, i messed up
static class Entry {
Entry getEntry(String s) {
if (Math.random() < 0.1) {
return new Entry();
}
else {
return null;
}
}
}
there
static class Entry {
Entry getEntry(String s) {
if (Math.random() < 0.1) {
return new Entry();
}
else {
return null;
}
}
}
void main() {
var m = new Entry();
var list = Arrays.stream("""
Head
head
body -> Head
body -> head
Body -> Head
Body -> head
root -> body -> Head
root -> body -> head
root -> Body -> Head
root -> Body -> head
Root -> body -> Head
Root -> body -> head
Root -> Body -> Head
Root -> Body -> head""".split("\n"))
.map(row -> row.split("->"))
.map(row -> Arrays.stream(row)
.map(String::strip)
.toList())
.toList();
IO.println(list);
for (var path : list) {
Entry e = m;
for (var entry : path) {
e = e.getEntry(entry);
if (e == null) {
break;
}
}
if (e != null) {
IO.println(path);
IO.println(e);
}
}
}
can you tell i'm tired?
ok but if i understand correctly that first part makes a list like
[["Head"],["body", "Head"] ] etc but i dont get how that nests the children
like you just loop over it
oh well you check one layer deep
but not 2 layers
or im dumb one of the 2
Optional.ofNullable(m)
.map(e -> e.getEntry("root"))
.map(e -> e.getEntry("body"))
.map(e -> e.getEntry("head"))
.orElseGet(null);
here is another option that gives ?.
like this is a more verbose version of that
ye but isnt that only one layer deep
then you get to the next layer
like lets take root body head
you first go into the root body head sequency
then you get an entry so you get root
you still have body and head
and then you exit the loop?
or you mean that i just add the other 2 layers
sorry i am getting pulled back to work
okay
eeeh
Little unknown trick
new TreeMap<String, ?>(String.CASE_INSENSITIVE_ORDER)
There, case insensitive strings in your map
ugh
it does have some issues if you start comparing entire maps to eachother though
but for lookups etc, it's great 😄
getEntry should be getChild
ye i get that
sorry still cant really come back to this yet
did you figure out what i was going for?
sounds like they were asking about alternatives to the elvis operator. a structure change could definitely help
but they could be working on legacy code for all we know
you need to understand im working with a mc codebase here so half the stuff i have to use are out of my control in the first place
sounds like they dont have much power in changing the structure
Ye I would if I could but I’m already making private stuff public so can’t expect mojang to make their stuff nice to use if I’m doing that lmao
thats what i was saying, "cant always change the structure". the alternative to the elvis operator in Java would be Optional
but its more used for exposing nullable values, not for working with them
people still do null checks & such in modern Java code, just usually dont statically
Objects.nonNull
so instead of if(member != null), its if(Objects.nonNull(member))
the idea is: "if you are given null, use null. if you are exposing values that may be nullable, expose Optional instead"
that way instead of receiving a nullable value, they receive an optional value. "this value may not exist" winds up being clear as day
What’s the difference between these
readability
thats it
nonNull performs basically the same check
its just more descriptive
"more descriptive" 🙄
they do the same thing though
a benefit would be allowing the API to handle null checking. thats the main idea
if null checking ever changed, nonNull would account for it
you wouldnt have to change your null check or anything, it would just work
its silly, pretty dumb IMO, but it does have some reasoning
null is being rid of anyways. null was a mistake
the billion dollar mistake
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W).
can read more about it, just look up Tony Hoare
Sir Charles Antony Richard Hoare (; born 11 January 1934), also known as C. A. R. Hoare, is a British computer scientist who has made foundational contributions to programming languages, algorithms, operating systems, formal verification, and concurrent computing. His work earned him the Turing Award, usually regarded as the highest distinction ...
thats the guy who invented null
imagine u have a pipeline that expects a predicate. then a method reference fits better in many cases
persons.stream()
.map(person::getFriend)
.filter(Objects::nonNull)
.forEach(...);
versus
persons.stream()
.map(person::getFriend)
.filter(p -> p != null)
.forEach(...);
i havent seenn it being used for normal ifs yet. but yeah. it was added together with other similar methods when method references were added with the stream api
Fair enough
oh god no
That has a serious issue
If you're quickly glancing over the code, the first one has a distinctive shape, something, something orange
You know because of that different color something is happening there immediately, just because null is a keyword and is highlighted differently
That's the only valid usecase for that method
ye true actually
you can always adjust syntax highlights. it shouldnt be a factor in the actual code design though
its pretty frequent in the standard lib, usually under requireNonNull
for example
JDK main-line development https://openjdk.org/projects/jdk - openjdk/jdk
yeah but thats requireNonNull
not nonNull
i.e. "i want to use this thing. btw, throw an exception if its null"
versus "is this thing null or not?"
requireNonNull definitely has uses, its great
but nonNull is mostly for when u need a Predicate id say
its a bit weird cuz itll probs throw an NPE regardless but ye
depends. its very useful for fail-fast
true i guess
like, in this case its meaningless:
Objects.requireNonNull(person).getName()
but in this case its good:
Person person = Objects.requireNonNull(persons.getFirst());
...
nameToPerson.put("john", person);
cause in this case u wouldnt necessarily get a NPE otherwise
ye true
and if, potentially many lines later only
ye
(a lot of these situations are covered by Optional as return type for methods already as well)
you can do a search over the standard lib to see it's uses
an example of nonNull being used in a non-reference way
JDK main-line development https://openjdk.org/projects/jdk - openjdk/jdk
the idea was, if you want null handling similar to other languages, the only option at the moment is making use of APIs like this
while there are ofc uses like that out in the wild, its not really sth ull encounter commonly
depends on the situation, as with most things
the core idea is pretty simple: rely on some form of an interface, even if its just a method
the difference is "API vs Language Spec"
You get both of these in kotlin
they went for default methods
theres a whole JEP explaining why they opted for default methods instead of extension methods
"the API designer should be in charge of scaling the interface, not the user"
thats basically the summary
this is probably one of the first JEPs where they bring up extensions
Project Lambda also includes virtual extension methods, which will address the long-standing limitation of not being able to add methods to widely-used interfaces because of source compatibility concerns.
very similar to how they implemented lambdas: very restricted, because they feel it would hurt productivity if it wasn't restricted
ah my bad, it wasnt a JEP that talked about it. it was a Brian Goetz lecture
but the idea still remains: Java opted for default methods as an alternative to extension methods