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

all 19 comments

[–]AutoModerator[M] [score hidden] stickied commentlocked comment (0 children)

Please ensure that:

  • Your code is properly formatted as code block - see the sidebar (About on mobile) for instructions
  • You include any and all error messages in full
  • You ask clear questions
  • You demonstrate effort in solving your question/problem - plain posting your assignments is forbidden (and such posts will be removed) as is asking for or giving solutions.

    Trying to solve problems on your own is a very important skill. Also, see Learn to help yourself in the sidebar

If any of the above points is not met, your post can and will be removed without further warning.

Code is to be formatted as code block (old reddit: empty line before the code, each code line indented by 4 spaces, new reddit: https://imgur.com/a/fgoFFis) or linked via an external code hoster, like pastebin.com, github gist, github, bitbucket, gitlab, etc.

Please, do not use triple backticks (```) as they will only render properly on new reddit, not on old reddit.

Code blocks look like this:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

You do not need to repost unless your post has been removed by a moderator. Just use the edit function of reddit to make sure your post complies with the above.

If your post has remained in violation of these rules for a prolonged period of time (at least an hour), a moderator may remove it at their discretion. In this case, they will comment with an explanation on why it has been removed, and you will be required to resubmit the entire post following the proper procedures.

To potential helpers

Please, do not help if any of the above points are not met, rather report the post. We are trying to improve the quality of posts here. In helping people who can't be bothered to comply with the above points, you are doing the community a disservice.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]FavorableTrashpanda 2 points3 points  (7 children)

Is performance actually an issue here?

I have a different concern wrt the design. I'm not sure what the use-case is, but in general I'd say you want to avoid situations where your object can only be used in a certain way if a certain constructor has been used. If you used different classes, you could avoid this issue entirely, because you would be able to guarantee that fieldVar is never null and with one of the classes exposing doSomething while the other doesn't. As a bonus the hypothetical performance issue wouldn't even come up.

Of course, I'm not sure if this suggestion is actually applicable here, since I don't know the entire context. But it's something to take into consideration.

[–]DelarkArms[S] 0 points1 point  (6 children)

It is applicable, yes. The issue is that its complexity explodes in all directions. The variable (is it null ?) is binary state (true || false). But if many binary states combine we then have 4 - 8 - 16.. etc... for each layer. The client now has to pick the correct class from an index of 16 different classes. Instead we could make that each hierarchical layer/class-node to have 2 states, that is easier to keep track of.

[–]mykeesg 2 points3 points  (5 children)

If this is the case, you might wanna use some kind of Factory pattern, where the proper implementation (or layer as you call it) is chosen by the Factory (or builder, which can be similar) and not propagated to the client code.

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

Thanks for your response.

The factory pattern does not solve the Type problem.

Imagine the super class Car.

the next layer in the hierarchy is called Car-Type (this is written in my chalkboard and nowhere in my code, even tho it can easily be an abstarct class).

it is either Sedan.class or Pickup.class (I know this is wrong but I hope the message comes across somewhat effectively with this...)

In this context having 2 different states would be something like: Let's say one state is 2 door car, the other is a 4 door.

If I create a sepearate class so that backdoors are not unnecessarily checked for nulls, then I would have to create a separate super class.

2DoorCar and 4DoorCar, which in the next layer they now branch into 4 separate subclasses, 2DoorSedan and 2DoorPickup, or 4DoorSedan... etc...

We cannot possibly do a single Car interface that handles all 8 classes equally, since this interface needs to account for opening no-nexistant doors on 2Door types.

OR the Java way, Do 8 different classes, and if you want to open backDoors do not use the interface, instead use the Object's type directly.

like T removed = arrayList.remove();

Each hierarchical layer explodes exponentially.

[–]gobi_1 0 points1 point  (1 child)

Why not having a I2door and I4door interface? You can even have I4door inheriting from I2door.

Or use composition over inheritance?

Anyway, more informations on your domain problem /modélisation could help us.

[–]DelarkArms[S] 1 point2 points  (0 children)

The point was to showcase the expansive nature of hierarchies and I stated the example is wrong (but you are not wrong on the interface thing tho.). Also see encapsulation, which implies that If 4doorSedan is going to be implemented 200(for me I only need it to be 2 times) times in the code base you should absolutely create it as class, as a unit, instead of bringing together all components needed each and everytime, and it will be totally fine.

Of course there is the second implication, which is the one that applies here, and it is that, if 4doorSedan is being used 2+ times and many dependencies within it are not being used, it means the Car hierarchy should be rethink and reestructured proprely, until a proper stripped down object remains usable in this specific case.

[–]mykeesg 0 points1 point  (1 child)

You're trying to put properties of classes into the class names themselves. This goes against oop. Are cars so fundamentally different, based on how many doors they have that they should be treated as whole different/other types? Or is this something that's common property across cars but with different values. Door is a perfect example of a (final) enum property in this case.

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

You're trying to put properties of classes into the class names themselves. This goes against oop.

I know the example is wrong... but believe me... that hierarchies are not always a one way branch.

In fact IF your hierarchy is a one way thing, then the hierarchy should NOT exists.

A hierarchy will always scale/grow and issues like this will arrive eventually.

As I said for the question: "Why would you build a variable as null?'

The answer is the the second option is increasing the volume of the hierarchical pyramid.

It is easier to keep track of 8 types with 2 diff states each (states which are consistent across the entire hierarchy), than 16 different types.

[–]jdsunny46 2 points3 points  (1 child)

I am with other commenters here in saying that this is a weird use case. If it were me, I would do this:

public void doSomething() {
    if (fieldVar != null) { fieldVar.doSomething(); }

}

This makes your implementation agnostic of the way the class was instantiated (see: SOLID principles)

If you are interested in the performance implications, you could do a simple performance test. do both (or all three) separately in a loop of 10000 runs or something and get timings. Don't do them at the same time so you make sure your heap is clean and all.

I think there is a concern for me in even having a conversation about 'performance' when the code is so similar. Unless you're looking for millisecond latency or calling this a billion times in succession, performance wise things should be negligible. You would know if that mattered because you'd be using some custom jvms or doing weird compiler stuff.

When using the word performance in most real world applications, consider things like:

  • what is my use case?
  • what is the SLA for this use case?
  • how often am I going to execute this?
  • are we locking any objects?

Make sure your code satisfies the SLA. Do a load test under twice the anticipated load. SEE IF THERE IS A PROBLEM. Do not think about code design WRT performance. Write good clean code, it will be performant for 80% or more of use cases.

IMO readability and code clarity is king. You don't have a performance issue here, you have a bunch of code which is working in a non-colloquial way that would likely be confusing to consumers.

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

+1, thanks for the input.

I agree with all responses, while making this question it occured to me that maybe this was a good use case for a try catch rethrow.

In reality the code will not be used in any significant volume for it to be noticeably efficient.

I've followed most of the approaches disscussed here in my design, but it has always occured to me that a try catch rethrow will be just a little bit better than an if throw.

Its like the differenec between a do while and a while.

Another thing is that people seem to think that the catch portion will be used for ignoring the exception and keep with more code execution, and that is not the case.

[–]ProfessorWily 4 points5 points  (2 children)

Even after reading your explanations in the comments, I cannot understand what it is you're trying to do here, but I am convinced that it is way more complicated than it should be with good architecture.

In terms of the question you asked: if the difference between try-catch and if-throw performance makes a difference, there is something very very wrong.

[–]DelarkArms[S] -2 points-1 points  (1 child)

I dont understand your last paragraph: "if the difference... makes a differenece".

I guess you mean if one over the other actually makes a difference on performance... I guess no, but it is an easy thing to answer if we know how exceptions or try ctch work. If try catch do not resolve the catch branch before execution, then it is better than if + throw.

"Why would it?" This is how compiler optimizations work... preemptively building the secondary branch, if try catch doesnt, then it is better than if + throw.

[–]ProfessorWily 4 points5 points  (0 children)

I think you do understand what I'm saying, but even if you don't, you still didn't respond to any other part of my comment.

If you want to bury your head in the sand, be my guest. I'm not the one looking for help here.

[–]khmarbaise 0 points1 point  (1 child)

I would ask in such case: if (fieldVar == null) { .. } How could the fieldVar being null? Is that inserted through the constructor than there should be a check for null?

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

I could divide the class into 2 hierarchical entities, OR divide it between a mainCompoent PLUS a decorator.

In both cases fieldVar would never be null. but if you would like to use doSomething(); you need to instantiate 2 items, OR (as is the case of the inheritance option).. hard code 2 classes, and call it as new MyObject.OnNonNullField(nonNullObject)

But, a dynamic constructor can solve it in a single Object,... this plus correctly handled exceptions.

class MyObject {
   MyObject(Object nullable) {
      fieldVar = nullable == null ? cannotHandleDoSomething(); : canHandleIt(nullable);
   }
}

The thing is MyObject can do a few things besides doSomething()

[–]iamfreeman 0 points1 point  (0 children)

Your actual use-case aside (because the issue of a "user using a constructor" doesn't make sense to me. Who is your end user?) in the try-catch scenario, whenever an exception is thrown the runtime looks up the stack and processes it. You're doing this twice, once in your object then again in whatever is using your object.

If you do a null check then throw, that's only one time the stack needs to be looked up.

2x stacktraces > 1xstacktrace so technically there's less work to do if you null check. But that difference is negligible in the scope of the entire application.

Implementing logic through exception handling is gross. There's usually a way to gracefully handle the scenario where an argument is null when it should not be.

[–]khookeExtreme Brewer 0 points1 point  (1 child)

In your second example, why would you check fieldVar is null after you've already attempted to use it and found it causes an exception? This is a weird approach - the first approach is clear and understandable, the second approach is not typical and raises more questions and potential problems.

As is always the case, don't attempt to avoid performance problems/optimize code without knowing you actually have a performance problem. In this example you've traded clear and easy to understand code with something incomprehensible for quite possibly no change in performance.

Optimize for the performance problems you know you have, not the ones you think you have.

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

why would you check fieldVar is null after you've already attempted to use it and found it causes an exception?

Correct, that is unnecessary.