I am often in a situation where I have a method where something can go wrong but an exception would not be right to use because it is not exceptional.
For example:
I am designing a monopoly game. The class Bank has a method buyHouse and a field which counts the number of houses left(there is 32 houses in monopoly). Something that could go wrong is a player buying a house when there is 0 left. How should I handle this. Here is 3 approaches I can come up with.
1. public void buyHouse(Player player, PropertyValue propertyValue)
{
if(houseCount < 0) throw new someException;
....
//Not really an exceptional situation
}
2. public boolean buyHouse(Player player, PropertyValue propertyValue)
{
if(houseCount < 0) return false;
....
//This I think is the most normal approach but changing something
//and returning if it was a success seems bad practice to me.
}
3. public boolean housesLeft()
{
if(houseCount > 0) return true;
return false;
//Introducing a new method. But now I expect the client to call this method
//first before calling buyHouse().
}
What would you do?
I would do 3 and 1 together. The proper usage of the API is to check if there are houses left before buying one. If, however, the developer forgot to do so, then throw a runtime exception.
If it is a multi-threaded situation (where many people are buying a house simultaneously) it gets more complicated. In that case, I would indeed consider a checked exception, if not a tryToBuyAHouse method that returns a boolean, but a runtime exception on the buyHouse method.
This is very similar to the idea of popping an item off of an empty stack... it is exceptional. You are doing something that should fail.
Think of exceptional situations as cases where you want to notify the programmer that something has gone wrong and you do not want them to ignore it. Using a simple boolean return value isn't "right" since the programmer can just ignore it. Also the idea of having a method that should be called to check that there are houses available is a good idea. But remember that programmers will, in some cases, forget to call it. In that case the exception serves to remind them that they need to call the method to check that a house exists before acquiring it.
So, I would provide the method to check that there are houses, and expect that people will call it and use the true/false return value. In the event that they do not call that method, or ignore the return value, I would throw an exception so that the game does not get put into a bad state.
I find the meaning of "exceptional" to be quite subjective. It means whatever you want it to mean. You're designing the interface to the function, you get to decide what is exceptional and what is not.
If you don't expect buyHouse to be invoked when houseCount is <= 0, then an exception here is fine. Even if you do expect it to be invoked, you can catch the exception in the caller to handle that situation.
If something works as expected 32 times in a row, and then fails to function as expected, I think that you could justify making it an exceptional condition if it was an isolated case.
Given the situation you describe, I think that using exceptions is not appropriate, as once 32 houses are sold the bank will continue to be out of them (this is the new "normal" state), and exception processing is actually pretty slow in Java compared to normal processing.
One thing you could do is more closely mirror the actual interaction. In Monopoly, the banker will simply tell you that you cannot buy a house if there are none left.
A potential model for this is as follows:
public House buy(Player player, PropertyValue propertyValue) {
House propertyHouse = null;
if (houseCount > 0) {
propertyHouse = new House(player, propertyValue);
houseCount--;
}
return propertyHouse;
}
That would also allow you to add behavior to the House object, and make the flow for requesting/buying a house a little more natural. If there are no houses available, you don't get one.
Either (1) or (2) is acceptable, depending on whether or not you consider "no houses to buy" a routine result or an exceptional condition.
(3) is a bad idea, for several reasons:
it breaks encapsulation (client has to know too much about internals of the Bank)
you'd still have to check for errors and do (1) or (2) in case the client screws up
it's problematic in multi-threaded situations
A couple of other options:
Your method could accept a number of houses requested parameter, and return the number of houses actually purchased, after checking the player's available balance and the number of houses available. Returning zero would be a perfectly acceptable possibility. You rely on calling code to check how many houses it actually got back, of course. (this is a variation on returning a boolean, where true/false indicate 1 or zero houses purchased, of course)
A variation on that theme would be to return a collection of House objects corresponding to the number of houses successfully purchased, which could be an empty collection. Presumably calling code would then be unable to act as if it had more House objects than you'd given it. (this is a variation on returning a House object, with null representing no houses purchased, and an object representing 1 house, and is often part of a general coding approach of preferring empty collections to null references)
Your method could return a HousePurchaseTransaction object which was itself queryable to determine the success or failure of the transaction, its actual cost, and so on.
A richer variation on that theme might be to make HousePurchaseTransaction abstract and derive two child classes: SuccessfulHousePurchase and FailedHousePurchase, so you could associate different behaviour with the two result conditions. Installing a house into a street might require you to pass a 'SuccessfulHousePurchase' object in order to proceed. (this avoids the danger of returning a null being the root of a later null reference error, and is a variant on the null object pattern)
In reality, I suspect the approach taken would depend on where you ended up allocating responsibility for placing the houses on the board, upgrading to hotels, enforcing even-build rules, limiting the number of houses purchased on a given street, and so on.
I would do something like this:
public boolean BuyHouse(Player player, PropertyValue propertyValue) {
// Get houseCount
if(houseCount <= 0) {
// Log this to your message queue that you want to show
// to the user (if it has a UI)
return false;
}
// Do other stuff if houses are left
}
PS: I am not familiar with java, I use C#
This question is hard to answer without the context of which entity has-a house. From a general design perspective, there is little semantic difference for the caller between (1) and (2) - both are try and check - but you are correct that (1) is to be shunned for wholly expectable state.
You decide a rule & exception here for user who use your API/methods:
housesLeft() can be called to check
the number of houses left before
buyHouse() is called. Calling
buyHouse() whenever the number of
house left is zero is an exception.
It is similar to checking before you access certain array element, you check the array length before you try t o access it, else an exception will be issue.
So it should looks like this:
if (housesLeft() > 0) buyHouse(...);
similar to
for (int i=0; i < arrayList.length; i++) System.out.println(arrayList[i]);
Remember that you can use
return houseCount > 0;
rather than
if(houseCount > 0) return true;
return false;
Related
Consider a Product with a quantity which can be increased and decreased by a given amount. The quantity should never become negative and if it is going to happen, the operation must be prohibited and the user warned.
public class Product{
private int quantity;
public Product() {
quantity = 10;
}
public void decreaseQuantity(int amount) {
int decreasedQuantity = quantity - amount;
if(decreasedQuantity < 0 )
throw new RuntimeException(String.format("Decrease quantity (%s) exceeds avaiable quantity (%s)",
amount, quantity));
quantity = decreasedQuantity;
}
}
For example if a product has quantity 10 and I try to remove 20, I throw a RuntimeException. SonarCloud suggests to replace the RuntimeException with a Custom exception, but I was wondering if there is a standard exception suitable for this case (Effective Java: Favor The Use of Standard Exceptions).
The most suitable exception seems to be IllegalStateException. From the javadoc
Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
and from Effective Java
IllegalStateException: This exception is used if, when a method is called, the state of the object is not valid for that operation. Potentially you have a filehandle and you call read before it has been opened.
However, it seems to me that there is a subtle difference between my example and what is assumed in the docs: it is not the state of the object itself that makes the operation illegal, it's the state of the object and the value of the input parameter. Reading usage examples (like What's the intended use of IllegalStateException?) the object is always in a state where the operation is rejected regardless of the input parameter.
There is nothing in the core java libraries that is a slam dunk. However, make your own exception is probably your best bet, it's a close race between that and using IllegalArgumentException.
RuntimeException
Ill advised for nebulous reasons. The primary reason not to use it, is because linter tools will yell at you. The reason they yell at you is twofold, and to determine whether the right move is to tell the linters to shut up, or to head their advice, is to focus on these 2 reasons:
The type name of the exception is itself information. For example, throw new NullPointerException("x is null") is dumb code to write (even though its common). It's superfluous - just new NullPointerException("x") is appropriate. RuntimeException conveys almost no information at all. You are mostly avoiding this trap: Whilst RuntimeException indeed conveys nearly nothing, the message of the exception says it all, therefore, the thing the linter is trying to stop from happening (throwing an exception that doesn't properly convey the nature of the problem) isn't happening, and thus you should consider just telling the linter to stop whining... except for:
The second reason you want a proper exception type is that you really, really don't want code that intends to catch this to have to do string analysis on an exception message. Thus, if there's any world in which you can foresee that some code wants to invoke your method and then react to the condition (of trying to subtract more than available) in any way other than blowing up all context, then you should be throwing an exception that means this specific condition and nothing else. RuntimeException is never appropriate to catch if your intent is to catch a specific condition (it's pretty much never appropriate, period - sometimes you want to run code and react to any problem regardless of its nature, but then catch (Exception e) is the appropriate catch block, or even Throwable. e.g. appservers and the like should be doing this.
IllegalArgumentException
The linters won't be yelling, but you're still not really getting the secondary benefit (that is, allow callers to catch this specific problem and not some other problem with the arguments). It's also 'mentally' slightly dubious: Your reasons for initially disregarding it are not wrong. Generally IAEs are understood to imply that the illegal argument is illegal regardless of the state of this object. But this isn't written in IAE's javadoc and isn't universally applied.
So, downsides are:
It's a bit of a push to force callers to catch (IllegalArgumentException e) to deal with wanting to react to subtracting more than is there. IAE is still too 'general'.
It could be lightly confusing.
Upside is simply:
It's already there.
IllegalStateException
I think this is strictly worse than IAE. It's mostly the same story, except here the confusion is that ISE is usually used to flag that the current state of the object is such that the operation you are trying to call is simply not available. In a tweaked way that's actually true (the object's state is that there are 3 items; therefore it is not in a state that decreaseQuantity(5) is an available operation right now), but it feels more confusing than IAE: ISE feels like the Product object itself is in an invalid state. I'd be assuming that the product is a legacy product that is not now or will ever be in stock again, or is some dummy product type (a Product object representing 'unknown product' or something similarly exotic).
But, same deal with IAE: The javadoc of ISE doesn't specifically spell out that you couldn't do it. Hence, if you would prefer to throw this, you could, it's not provably incorrect, at worst it's simply bad code style. A linter tool is never going to fault you for it, or if it does, the linter tool is wrong.
write your own
Advantages:
There's no chance that users of your library bring faulty assumptions (that IAE means: Argument is illegal regardless of state); that makes it less confusing.
If code intends to call your method and write a catch clause specifically for the condition of removing more than is there, then this is definitely the nicest answer. This:
try {
product.decreaseQuantity(5);
} catch (QuantityInsufficientException e) {
ui.showOrderingError("Regretfully we don't have this item in stock at the quantity you want");
}
Is slightly more readable than catch (IllegalArgumentException), and more importantly, is more reliable: IAE is such an oft-used exception that you're going to one day edit the decreaseQuantity method and introduce a code path that throws IAE for some other reason and now you have a very hard to find bug.
Conclusion
I'd be writing your own. Yes, it's a bit of a drag to have to write the source file, but you can let your IDE (or Project Lombok for maximum boilerplate busting) generate the entire file and you probably never have to look at InsufficientQuantityException.java ever again.
java.lang.IllegalArgumentException is the right answer in this case.
This example is equivalent to the following one from Effective Java - Third Edition (page 301):
Consider the case of
an object representing a deck of cards, and suppose there were a method to deal a
hand from the deck that took as an argument the size of the hand. If the caller
passed a value larger than the number of cards remaining in the deck, it could be
construed as an IllegalArgumentException (the handSize parameter value is too
high) or an IllegalStateException (the deck contains too few cards). Under
these circumstances, the rule is to throw IllegalStateException if no argument
values would have worked, otherwise throw IllegalArgumentException.
TheIllegalStateException is not correct because the state of the object does not prevent to invoke decreaseQuantity: you can invoke it, just use an appropriate input value.
sometimes it would be convenient to have an easy way of doing the following:
Foo a = dosomething();
if (a != null){
if (a.isValid()){
...
}
}
My idea was to have some kind of static “default” methods for not initialized variables like this:
class Foo{
public boolean isValid(){
return true;
}
public static boolean isValid(){
return false;
}
}
And now I could do this…
Foo a = dosomething();
if (a.isValid()){
// In our example case -> variable is initialized and the "normal" method gets called
}else{
// In our example case -> variable is null
}
So, if a == null the static “default” methods from our class gets called, otherwise the method of our object gets called.
Is there either some keyword I’m missing to do exactly this or is there a reason why this is not already implemented in programming languages like java/c#?
Note: this example is not very breathtaking if this would work, however there are examples where this would be - indeed - very nice.
It's very slightly odd; ordinarily, x.foo() runs the foo() method as defined by the object that the x reference is pointing to. What you propose is a fallback mechanism where, if x is null (is referencing nothing) then we don't look at the object that x is pointing to (there's nothing its pointing at; hence, that is impossible), but that we look at the type of x, the variable itself, instead, and ask this type: Hey, can you give me the default impl of foo()?
The core problem is that you're assigning a definition to null that it just doesn't have. Your idea requires a redefinition of what null means which means the entire community needs to go back to school. I think the current definition of null in the java community is some nebulous ill defined cloud of confusion, so this is probably a good idea, but it is a huge commitment, and it is extremely easy for the OpenJDK team to dictate a direction and for the community to just ignore it. The OpenJDK team should be very hesitant in trying to 'solve' this problem by introducing a language feature, and they are.
Let's talk about the definitions of null that make sense, which definition of null your idea specifically is catering to (at the detriment of the other interpretations!), and how catering to that specific idea is already easy to do in current java, i.e. - what you propose sounds outright daft to me, in that it's just unneccessary and forces an opinion of what null means down everybody's throats for no reason.
Not applicable / undefined / unset
This definition of null is exactly how SQL defines it, and it has the following properties:
There is no default implementation available. By definition! How can one define what the size is of, say, an unset list? You can't say 0. You have no idea what the list is supposed to be. The very point is that interaction with an unset/not-applicable/unknown value should immediately lead to a result that represents either [A] the programmer messed up, the fact that they think they can interact with this value means they programmed a bug - they made an assumption about the state of the system which does not hold, or [B] that the unset nature is infectuous: The operation returns the notion 'unknown / unset / not applicable' as result.
SQL chose the B route: Any interaction with NULL in SQL land is infectuous. For example, even NULL = NULL in SQL is NULL, not FALSE. It also means that all booleans in SQL are tri-state, but this actually 'works', in that one can honestly fathom this notion. If I ask you: Hey, are the lights on?, then there are 3 reasonable answers: Yes, No, and I can't tell you right now; I don't know.
In my opinion, java as a language is meant for this definition as well, but has mostly chosen the [A] route: Throw an NPE to let everybody know: There is a bug, and to let the programmer get to the relevant line extremely quickly. NPEs are easy to solve, which is why I don't get why everybody hates NPEs. I love NPEs. So much better than some default behaviour that is usually but not always what I intended (objectively speaking, it is better to have 50 bugs that each takes 3 minutes to solve, than one bug that takes an an entire working day, by a large margin!) – this definition 'works' with the language:
Uninitialized fields, and uninitialized values in an array begin as null, and in the absence of further information, treating it as unset is correct.
They are, in fact, infectuously erroneous: Virtually all attempts to interact with them results in an exception, except ==, but that is intentional, for the same reason in SQL IS NULL will return TRUE or FALSE and not NULL: Now we're actually talking about the pointer nature of the object itself ("foo" == "foo" can be false if the 2 strings aren't the same ref: Clearly == in java between objects is about the references itself and not about the objects referenced).
A key aspect to this is that null has absolutely no semantic meaning, at all. Its lack of semantic meaning is the point. In other words, null doesn't mean that a value is short or long or blank or indicative of anything in particular. The only thing it does mean is that it means nothing. You can't derive any information from it. Hence, foo.size() is not 0 when foo is unset/unknown - the question 'what is the size of the object foo is pointing at' is unanswerable, in this definition, and thus NPE is exactly right.
Your idea would hurt this interpretation - it would confound matters by giving answers to unanswerable questions.
Sentinel / 'empty'
null is sometimes used as a value that does have semantic meaning. Something specific. For example, if you ever wrote this, you're using this interpretation:
if (x == null || x.isEmpty()) return false;
Here you've assigned a semantic meaning to null - the same meaning you assigned to an empty string. This is common in java and presumably stems from some bass ackwards notion of performance. For example, in the eclipse ecj java parser system, all empty arrays are done with null pointers. For example, the definition of a method has a field Argument[] arguments (for the method parameters; using argument is the slightly wrong word, but it is used to store the param definitions); however, for methods with zero parameters, the semantically correct choice is obviously new Argument[0]. However, that is NOT what ecj fills the Abstract Syntax Tree with, and if you are hacking around on the ecj code and assign new Argument[0] to this, other code will mess up as it just wasn't written to deal with this.
This is in my opinion bad use of null, but is quite common. And, in ecj's defense, it is about 4 times faster than javac, so I don't think it's fair to cast aspersions at their seemingly deplorably outdated code practices. If it's stupid and it works it isn't stupid, right? ecj also has a better track record than javac (going mostly by personal experience; I've found 3 bugs in ecj over the years and 12 in javac).
This kind of null does get a lot better if we implement your idea.
The better solution
What ecj should have done, get the best of both worlds: Make a public constant for it! new Argument[0], the object, is entirely immutable. You need to make a single instance, once, ever, for an entire JVM run. The JVM itself does this; try it: List.of() returns the 'singleton empty list'. So does Collections.emptyList() for the old timers in the crowd. All lists 'made' with Collections.emptyList() are actually just refs to the same singleton 'empty list' object. This works because the lists these methods make are entirely immutable.
The same can and generally should apply to you!
If you ever write this:
if (x == null || x.isEmpty())
then you messed up if we go by the first definition of null, and you're simply writing needlessly wordy, but correct, code if we go by the second
definition. You've come up with a solution to address this, but there's a much, much better one!
Find the place where x got its value, and address the boneheaded code that decided to return null instead of "". You should in fact emphatically NOT be adding null checks to your code, because it's far too easy to get into this mode where you almost always do it, and therefore you rarely actually have null refs, but it's just swiss cheese laid on top of each other: There may still be holes, and then you get NPEs. Better to never check so you get NPEs very quickly in the development process - somebody returned null where they should be returning "" instead.
Sometimes the code that made the bad null ref is out of your control. In that case, do the same thing you should always do when working with badly designed APIs: Fix it ASAP. Write a wrapper if you have to. But if you can commit a fix, do that instead. This may require making such an object.
Sentinels are awesome
Sometimes sentinel objects (objects that 'stand in' for this default / blank take, such as "" for strings, List.of() for lists, etc) can be a bit more fancy than this. For example, one can imagine using LocalDate.of(1800, 1, 1) as sentinel for a missing birthdate, but do note that this instance is not a great idea. It does crazy stuff. For example, if you write code to determine the age of a person, then it starts giving completely wrong answers (which is significantly worse than throwing an exception. With the exception you know you have a bug faster and you get a stacktrace that lets you find it in literally 500 milliseconds (just click the line, voila. That is the exact line you need to look at right now to fix the problem). It'll say someone is 212 years old all of a sudden.
But you could make a LocalDate object that does some things (such as: It CAN print itself; sentinel.toString() doesn't throw NPE but prints something like 'unset date'), but for other things it will throw an exception. For example, .getYear() would throw.
You can also make more than one sentinel. If you want a sentinel that means 'far future', that's trivially made (LocalDate.of(9999, 12, 31) is pretty good already), and you can also have one as 'for as long as anyone remembers', e.g. 'distant past'. That's cool, and not something your proposal could ever do!
You will have to deal with the consequences though. In some small ways the java ecosystem's definitions don't mesh with this, and null would perhaps have been a better standin. For example, the equals contract clearly states that a.equals(a) must always hold, and yet, just like in SQL NULL = NULL isn't TRUE, you probably don't want missingDate.equals(missingDate) to be true; that's conflating the meta with the value: You can't actually tell me that 2 missing dates are equal. By definition: The dates are missing. You do not know if they are equal or not. It is not an answerable question. And yet we can't implement the equals method of missingDate as return false; (or, better yet, as you also can't really know they aren't equal either, throw an exception) as that breaks contract (equals methods must have the identity property and must not throw, as per its own javadoc, so we can't do either of those things).
Dealing with null better
There are a few things that make dealing with null a lot easier:
Annotations: APIs can and should be very clear in communicating when their methods can return null and what that means. Annotations to turn that documentation into compiler-checked documentation is awesome. Your IDE can start warning you, as you type, that null may occur and what that means, and will say so in auto-complete dialogs too. And it's all entirely backwards compatible in all senses of the word: No need to start considering giant swaths of the java ecosystem as 'obsolete' (unlike Optional, which mostly sucks).
Optional, except this is a non-solution. The type isn't orthogonal (you can't write a method that takes a List<MaybeOptionalorNot<String>> that works on both List<String> and List<Optional<String>>, even though a method that checks the 'is it some or is it none?' state of all list members and doesn't add anything (except maybe shuffle things around) would work equally on both methods, and yet you just can't write it. This is bad, and it means all usages of optional must be 'unrolled' on the spot, and e.g. Optional<X> should show up pretty much never ever as a parameter type or field type. Only as return types and even that is dubious - I'd just stick to what Optional was made for: As return type of Stream terminal operations.
Adopting it also isn't backwards compatible. For example, hashMap.get(key) should, in all possible interpretations of what Optional is for, obviously return an Optional<V>, but it doesn't, and it never will, because java doesn't break backwards compatibility lightly and breaking that is obviously far too heavy an impact. The only real solution is to introduce java.util2 and a complete incompatible redesign of the collections API, which is splitting the java ecosystem in twain. Ask the python community (python2 vs. python3) how well that goes.
Use sentinels, use them heavily, make them available. If I were designing LocalDate, I'd have created LocalDate.FAR_FUTURE and LocalDate_DISTANT_PAST (but let it be clear that I think Stephen Colebourne, who designed JSR310, is perhaps the best API designer out there. But nothing is so perfect that it can't be complained about, right?)
Use API calls that allow defaulting. Map has this.
Do NOT write this code:
String phoneNr = phoneNumbers.get(userId);
if (phoneNr == null) return "Unknown phone number";
return phoneNr;
But DO write this:
return phoneNumbers.getOrDefault(userId, "Unknown phone number");
Don't write:
Map<Course, List<Student>> participants;
void enrollStudent(Student student) {
List<Student> participating = participants.get(econ101);
if (participating == null) {
participating = new ArrayList<Student>();
participants.put(econ101, participating);
}
participating.add(student);
}
instead write:
Map<Course, List<Student>> participants;
void enrollStudent(Student student) {
participants.computeIfAbsent(econ101,
k -> new ArrayList<Student>())
.add(student);
}
and, crucially, if you are writing APIs, ensure things like getOrDefault, computeIfAbsent, etc. are available so that the users of your API don't have to deal with null nearly as much.
You can write a static test() method like this:
static <T> boolean test(T object, Predicate<T> validation) {
return object != null && validation.test(object);
}
and
static class Foo {
public boolean isValid() {
return true;
}
}
static Foo dosomething() {
return new Foo();
}
public static void main(String[] args) {
Foo a = dosomething();
if (test(a, Foo::isValid))
System.out.println("OK");
else
System.out.println("NG");
}
output:
OK
If dosomething() returns null, it prints NG
Not exactly, but take a look at Optional:
Optional.ofNullable(dosomething())
.filter(Foo::isValid)
.ifPresent(a -> ...);
down bellow you can see two example methods, which are structured in the same way, but have to work with completely different integers.
You can guess if the code gets longer, it is pretty anoying to have a second long method which is doing the same.
Do you have any idea, how i can combine those two methods without using "if" or "switch" statements at every spot?
Thanks for your help
public List<> firstTestMethod(){
if(blabla != null){
if(blabla.getChildren().size() > 1){
return blabla.getChildren().subList(2, blabla.getChildren().size());
}
}
return null;
}
And:
public List<> secondTestMethod(){
if(blabla != null){
if(blabla.getChildren().size() > 4){
return blabla.getChildren().subList(0, 2);
}
}
return null;
}
Attempting to isolate common ground from 2 or more places into its own Helper method is not a good idea if you're just looking at what the code does without any context.
The right approach is first to define what you're actually isolating. It's not so much about the how (the fact that these methods look vaguely similar suggests that the how is the same, yes), but the why. What do these methods attempt to accomplish?
Usually, the why is also mostly the same. Rarely, the why is completely different, and the fact that the methods look similar is a pure coincidence.
Here's a key takeaway: If the why is completely different but the methods look somewhat similar, you do not want to turn them into a single method. DRY is a rule of thumb, not a commandment!
Thus, your question isn't directly answerable, because the 2 snippets are so abstractly named (blabla isn't all that informative), it's not possible to determine with the little context the question provides what the why might be.
Thus, answer the why question first, and usually the strategy on making a single method that can cater to both snippets here becomes trivial.
Here is an example answer: If list is 'valid', return the first, or last, X elements inside it. Validity is defined as follows: The list is not null, and contains at least Z entries. Otherwise, return null.
That's still pretty vague, and dangerously close to a 'how', but it sounds like it might describe what you have here.
An even better answer would be: blabla represents a family; determine the subset of children who are eligible for inheriting the property.
The reason you want this is twofold:
It makes it much easier to describe a method. A method that seems to do a few completely unrelated things and is incapable of describing the rhyme or reason of any of it cannot be understood without reading the whole thing through, which takes a long time and is error-prone. A large part of why you want methods in the first place is to let the programmer (the human) abstract ideas away. Instead of remembering what these 45 lines do, all you need to remember is 'fetch the eligible kids'.
Code changes over time. Bugs are found and need fixing. External influences change around you (APIs change, libraries change, standards change). Feature requests are a thing. Without the why part it is likely that one of the callers of this method grows needs that this method cannot provide, and then the 'easiest' (but not best!) solution is to just add the functionality to this method. The method will eventually grow into a 20 page monstrosity doing completely unrelated things, and having 50 parameters. To guard against this growth, define what the purpose of this method is in a way that is unlikely to spiral into 'read this book to understand what all this method is supposed to do'.
Thus, your question is not really answerable, as the 2 snippets do not make it obvious what the common thread might be, here.
Why do these methods abuse null? You seem to think null means empty list. It does not. Empty list means empty list. Shouldn't this be returning e.g. List.of instead of null? Once you fix that up, this method appears to simply be: "Give me a sublist consisting of everything except the first two elements. If the list is smaller than that or null, return an empty list", which is starting to move away from the 'how' and slowly towards a 'what' and 'why'. There are only 2 parameters to this generalized concept: The list, and the # of items from the start that need to be omitted.
The second snippet, on the other hand, makes no sense. Why return the first 3 elements, but only if the list has 5 or more items in it? What's the link between 3 and 5? If the answer is: "Nothing, it's a parameter", then this conundrum has far more parameters than the first snippet, and we see that whilst the code looks perhaps similar, once you start describing the why/what instead of the how, these two jobs aren't similar at all, and trying to shoehorn these 2 unrelated jobs into a single method is just going to lead to bad code now, and worse code later on as changes occur.
Let's say instead that this last snippet is trying to return all elements except the X elements at the end, returning an empty list if there are fewer than X. This matches much better with the first snippet (which does the same thing, except replace 'at the end' with 'at the start'). Then you could write:
// document somewhere that `blabla.getChildren()` is guaranteed to be sorted by age.
/** Returns the {#code numEldest} children. */
public List<Child> getEldest(int numEldest) {
if (numEldest < 0) throw new IllegalArgumentException();
return getChildren(numEldest, true);
}
/** Returns all children except the {#code numEldest} ones. */
public List<Child> getAllButEldest(int numEldest) {
if (numEldest < 0) throw new IllegalArgumentException();
return getChildren(numEldest, false);
}
private List<Child> getChildren(int numEldest, boolean include) {
if (blabla == null) return List.of();
List<Child> children = blabla.getChildren();
if (numEldest >= children.size()) return include ? children : List.of();
int startIdx = include ? 0 : numEldest;
int endIdx = include ? numEldest : children.size();
return children.subList(startIdx, endIdx);
}
Note a few stylistic tricks here:
boolean parameters are bad, because why would you know 'true' matches up with 'I want the eldest' and 'false' matches up with 'I want the youngest'? Names are good. This snippet has 2 methods that make very clear what they do, by using names.
That 'when extracting common ground, define the why, not the how' is a hierarchical idea - apply it all the way down, and as you get further away from the thousand-mile view, the what and how become more and more technical. That's okay. The more down to the details you get, the more private things should be.
By having defined what this all actually means, note that the behaviour is subtly different: If you ask for the 5 eldest children and there are only 4 children, this returns those 4 children instead of null. That shows off some of the power of defining the 'why': Now it's a consistent idea. Returning all 4 when you ask for 'give me the 5 eldest', is no doubt 90%+ of all those who get near this code would assume happens.
Preconditions, such as what comprises sane inputs, should always be checked. Here, we check if the numEldest param is negative and just crash out, as that makes no sense. Checks should be as early as they can reasonably be made: That way the stack traces are more useful.
You can pass objects that encapsulate the desired behavior differences at various points in your method. Often you can use a predefined interface for behavior encapsulation (Runnable, Callable, Predicate, etc.) or you may need to define your own.
public List<> testMethod(Predicate<BlaBlaType> test,
Function<BlaBlaType, List<>> extractor)
{
if(blabla != null){
if(test.test(blabla)){
return extractor.apply(blabla);
}
}
return null;
}
You could then call it with a couple of lambdas:
testMethod(
blabla -> blabla.getChildren().size() > 1,
blabla -> blabla.getChildren().subList(2, blabla.getChildren().size())
);
testMethod(
blabla -> blabla.getChildren().size() > 4,
blabla -> blabla.getChildren().subList(0, 2)
);
Here is one approach. Pass a named boolean to indicate which version you want. This also allows the list of children to be retrieved independent of the return. For lack of more meaningful names I choose START and END to indicate which parts of the list to return.
static boolean START = true;
static boolean END = false;
public List<Children> TestMethod(boolean type) {
if (blabla != null) {
List<Children> list = blabla.getChildren();
int size = list.size();
return START ?
(size > 1 ? list.subList(0, 2) : null) :
(size > 4 ? list.subList(2, size) :
null);
}
return null;
}
I'm trying to create a condition for the variable price to not be less than 0 in order to be valid using a constructor
This is my code
public void setPrice(){
if(price > 0){
System.out.println("Valid value");}
else{
System.out.println("Error");} }
Is there a different way to do it other than if statement?
If this is an internal check (e.g. it's a programming error at this point if it is not a positive price) you can use assert. Something like:
assert price > 0 : "Price must be positive."
If this is checking externally generated input an exception is a better option:
if (price <= 0) { throw new IllegalArgumentException("Price must be positive"); }
This still uses an if. Often these types of validation methods are put in utility methods. For instance guava has Preconditions:
Preconditions.checkArgument(price > 0, "Price must be positive");
Lastly there are validation frameworks where you setup your object and it checks that all of the conditions are satisfied (example: http://beanvalidation.org/)
I want to make sure that the value of price cant be less than 0 [...].
Is there a different way to do it other than if statement?
No.
However, what you are doing is simply printing an error message and continuing to use the invalid value. That does not achieve what you require.
Here's what I think you should do:
public void setPrice(int price){
if (price <= 0) {
throw new IllegalArgumentException("price not > 0");
}
// set the price
}
If the price value is invalid, an exception is thrown and normal flow control is "interrupted". You can catch and handle the exception in (for example) the method that calls this one. Depending on where this is code is used the exception handler might ask the user for a correct value, reject the current request, skip a "record" in an input file and so on. But the logic for doing that ... and even for reporting the problem is not the concern of the setPrice method. This method is only responsible for checking and setting the price.
Alternatively, you can let the application terminate. That is what would happen here. IllegalArgumentException is an unchecked exception which means that the compiler won't insist that you do something about it.
You can do the same thing in a constructor. But note that if a constructor terminates with an exception, the object that it was creating won't be completely initialized. Usually it is thrown away.
#Jay Anderson suggests using assert. This is a possible solution, but it is probably not appropriate here. The problem is that checking of assert assertions can be turned off via a command line option. (And indeed, assertion checking is "off" by default)
You don't want people to be able turn off checks of user-supplied values.
You don't want people to be able turn off checks of values supplied by other peoples' software.
You don't want people to be able turn off checks of values supplied by other parts of your system.
Really, assertions are only appropriate if you are sure its is OK to run in production without the checks being performed ... at all. My recommendation would be not to use them at all. Instead use (separate) unit testing to pick up problems in your code.
Bellow is some pseudo code of the constructor you have defined.
public nameOfClass(type param){
if(param > 0){
throw new IllegalArgumentException("Error parameter may not be lower than 0");
}
}
I believe this is how the constructor would work if you did not want the parameter to be less than zero
I also believe that and if statement is almost certainly the best way to go about this.
I inherited a java application that processes requests and throws an exception if it determines a request should be cancelled. Exceptions have been convenient for the previous developer because they are an easy way to exit out of a tree of logic that no longer applies (yes a goto) and it prints a stack trace to the log which is good info to have. It seems to be the consenus on forums and blogs that exceptions should not be used for flow control and over half of the requests processed are cancelled, so they're definitely not exceptional situations. One argument is performance, which doesn't apply because our exception-ful code has run fast enough for years. Another argument is that the goto-ness of it is not clear, which I agree with. My question is: What is the alternative. The only thing I can think of is to have every method return true if processing should continue or false if it shouldn't. This seems like it would hugely bloat my code changing this:
checkSomething();
checkSomethingElse();
into this:
boolean continueProcessing = false;
continueProcessing = checkSomething();
if (!continueProcessing) {
return false;
}
continueProcessing = checkSomethingElse();
if (!continueProcessing) {
return false;
}
And then what if the method is supposed to return something? Any guidance would be great. I'd really like to observe whatever "best practices" are available.
Update:
Another bit I probably should have mentioned in the first place is that a request is cancelled more than 50% of the time and does not mean something didn't go right, it means the request wasn't needed after all.
In your scenario, the alternatives are throwing an exception and returning a result.
Which is best (and which is "best practice") depends on whether the failure of the "check..." methods should be classed as normal or exceptional. To some degree this is a judgement call that you have to make. In making that call there are a couple of things to bear in mind:
Creating + throwing + catching an exception is roughly 3 orders of magnitude SLOWER than testing a boolean result.
The big problem with returning status codes is that it is easy to forget to test them.
In summary, best practice is to not use exceptions to implement normal flow control, but it is up to you to decide where the borderline between normal and exceptional is.
Without seeing the real code / context, my gut feeling is that this is likely to be an appropriate place to use exceptions.
See How slow are Java exceptions? for a great discussion on this topic.
tl;dr
Separation of Concerns, and IMO you should do this:
continue = checkSomething() && checkSomethingElse();
or perhaps there are other design problems in the code.
What's the concern of the function -- as you want to define it (this can be a subjective question)? If the error fits into the function's concern, then don't throw an exception. If you are confused about whether or not the error fits into the concern, then perhaps the function is trying to accomplish too many concerns on its own (bad design).
Error control options:
don't report error. It either is handled directly by function or doesn't matter enough
return value is
null instead of an object
the error information (perhaps even a different data type than the object returned on success).
an argument passed in will be used to store error data.
trigger an event
call a closure passed to function if an error occurs.
throw an exception. (I'm arguing this should usually only be done if it's not a part of the arbitrarily defined purpose of the function)
If the purpose of the code is to check some state, then knowing that the state is false is directly the point of the function. Don't throw an exception, but return false.
That's what it looks like you are wanting. You have process X which is running checkers Y and Z. Control flow for process X (or any calling process) is not the same concern as checking states of a system.
How about
if (!checkSomething()) return false;
if (!checkSomethingElse()) return false;
No need for the flag if you exit early.
int error = 0;
do
{//try-alt
error = operation_1(); if(error > 0){break;}
error = operation_2(); if(error > 0){break;}
error = operation_3(); if(error > 0){break;}
}while(false);
switch(error) //catch-alt
{
case 1: handle(1); break;
case 2: handle(2); break;
case 3: handle(3); break;
}