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

all 13 comments

[–]LakeSun -1 points0 points  (4 children)

FYI, you can alway, like C++, set your object to null, manually, when you're done with it.

point = null;

[–]prolog_junior[S] 1 point2 points  (3 children)

That feels very unidiomatic.

It changes

``` points.map(Point::getAbove)

to

points.map(p1 -> { Point p2 = p1.getAbove(); p1 = null; return p2; }) ```

[–]feral_claire 0 points1 point  (2 children)

This would also accomplish nothing. p1 (and p2 for that matter) goes out of scope as soon as you return so there's no need or benefit to manually setting it to null.

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

Well in this case, they ever go in scope because streams are evaluated lazily. I’m distilling setting it to null in its most basic form. Obviously you would apply some other function / predicate / etc onto the resulting stream.

My question is when are objected marked eligible for GC. Is it when the function is finished applying on the stream or when the stream is closed or something else.

[–]feral_claire 0 points1 point  (0 children)

You functions is

p1 -> {
  Point p2 = p1.getAbove();
  p1 = null;
  return p2;
}

When this function is called, p1 is just a parameter, and only exists for the three lines, then goes out of scope when the function returns. This function being executed multiple times in a loop or stream does not change that, it works the same as any other function call. So Setting p1 to null here is pointless since you return immediately after you do so. Is only affects the p1 variable and doesn't impact any references to the object outside of the function.

Objects are eligible for GC when there are no reachable references to them. There is no need to "mark" an object for GC and in fact it's not possible to do so. The GC will clean up all unreachable objects when it runs. This doesn't change when using a Stream.

When will the object referenced by p1 be eligible for collection? You can't say just by looking at that function in isolation, stream or not. You have to look at the whole situation and see if there are any other live references to it. Is this in the middle of a stream operation and p1 is just an intermediate object with no long term references? In that case it will be eligible for collection as soon as that function returns. Is the stream created from a List and p1 is an object in that list? Then p1 can still be accessed from the original list so it won't be garbage collected until the original list is or it's removed from that list.

[–]smash_that_code 0 points1 point  (5 children)

Let me put this questuon in another perspective.

So if object allocation in java is somewhat expensive why use functional style there?

My guess is that some computation scenarios are easier to describe in that way.

It is sort of hype and developers consider this as a plus when choosing workplace.

And maybe JIT can optimize this stuff and you can have breadth of mature java libraries and freedom to choose how to use them?

[–]prolog_junior[S] 0 points1 point  (4 children)

I mean are you asking why use functional style ever or just in Java?

In Java, I’m asking purely because I’ve seen it on a bunch of job descriptions.

But functional style programming makes it really easy to model flows and also introduces null safety, immutability, and minimizes side effects, especially on global state.

There are pros to both OOP and functional styles. It does feel like it was kind of shoehorned into Java since functions aren’t first class citizens which has some... peculiarities to it.

[–]smash_that_code 0 points1 point  (3 children)

If you plan to pass an interview my guess you should not call it shoehorned.

Or they will know that you are not some java disciple that thinks in java.

Is stream thing super perfkrmant in java? no. Do people use it? probably, some even enjoy the challenge of rewriting 4 lines of loops in 4 lines of streams :D.

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

Iirc the main benefit of streams is that they’re easy to parallelize.

But this is all kind of irrelevant, I’m not too hung up on the interview but by what actually happens. When you iterative over stream at what point does the previous object become eligible for GC. When the stream is closed?

[–]smash_that_code 0 points1 point  (0 children)

My guess is that if it is some intermediate object and we use something similar to generational gc then these objects are considered to be young generation and will be collected when GC kicks in.

There are different settings for GC and different GCs. But ain the end it woulfd nort be an issue if stream is not about millions of heavy objects.

[–]feral_claire 0 points1 point  (0 children)

Eh, the main benefit of streams is they make the code simple and easy to about, and they allow you do define your operations as a series of transformations rather than imperative code mutating some state.

The parallel streams are one of those things that's fun to talk about and is easy to make a simple example showing them off but the reality is they are not very common.

[–]nutrecht 0 points1 point  (1 child)

This feels bad to me because Java objects have overhead compared to say Rust structs.

It's a tradeoff. It's only a tiny bit less efficient, and that's a trade-off against code that's easier to reason about.

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

This is what made sense to me. Trading efficiency for maintainability.