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;
}
Related
I'm trying to delete the middle node from a linked list given access to that node. I'm wondering if there is a difference between the two methods below, or do they accomplish the same thing?
public boolean deleteMiddle(Node middle){
Node next = middle.next; //line 2
middle.data = next.data;
middle.next = next.next;
return true;
}
public boolean deleteMiddle(Node middle){
middle.data = middle.next.data;
middle.next = middle.next.next;
return true;
}
The first method is what the textbook recommended but it seems like creating the Node "next" in the first method(line 2) is an unnecessary line of code.
I think you're probably right that they are equivalent (or certainly look that way)
In both cases it looks like there is a null pointer exception (on next.next) if the item you're deleting is the last in the list (e.g. if next is null then next.next is an error).
And if you get passed null of course that's also going to be a NPE.
creating the Node "next" in the first method(line 2) is an unnecessary line of code.
Both snippets achieve the same result.
But what the extra variable assignment (it does not "create a Node", it just assigns a new name to an existing one) does is avoiding to call middle.next twice, avoiding doing the same "calculation" twice.
In this example that won't make any real difference, but in general, it can be a usual performance optimization to avoid redundant work (especially if method calls are involved that do some "heavy lifting"). Before engaging in these adventures, though, one should think about if it is worth making the code potentially less legible, especially given that the JVM will try to do all kinds of optimization automatically. So apply this mindset only to simple patterns or real bottlenecks.
On top of that, giving names to intermediate results can also lead to more self-explanatory code (also not much difference here).
Final remarks: Sometimes (but not here) it is necessary to introduce extra variables to store things temporarily that would otherwise be overwritten in the course of the operation, such as the famous int h = x; x = y; y = h; example.
Yes, they're equivalent. I prefer the first one because it avoids the repetition of the expression middle.next.
As #Rick pointed out, when middle is the last element, you'll get an NPE in both cases.
I've seen code as below:
if (!substanceList.isEmpty() && (substanceList.size() > 0))
{
substanceText = createAmountText(substanceList);
}
Would the following be a valid refactor?
if (!substanceList.isEmpty())
{
substanceText = createAmountText(substanceList);
}
I would be grateful for an explanation of the above code and whether the second version may cause errors?
If in doubt, read the Javadoc:
Collection.isEmpty():
Returns true if this collection contains no elements.
Collection.size():
Returns the number of elements in this collection
So, assuming the collection is implemented correctly:
collection.isEmpty() <=> collection.size() == 0
Or, conversely:
!collection.isEmpty() <=> collection.size() != 0
Since the number of elements should only be positive, this means that:
!collection.isEmpty() <=> collection.size() > 0
So yes, the two forms are equivalent.
Caveat: actually, they're only equivalent if your collection isn't being modified from another thread at the same time.
This:
!substanceList.isEmpty() && (substanceList.size() > 0)
is equivalent to, by the logic I present above:
!substanceList.isEmpty() && !substanceList.isEmpty()
You can only simplify this to
!substanceList.isEmpty()
if you can guarantee that its value doesn't change in between evaluations of substanceList.isEmpty().
Practically, it is unlikely that you need to care about the difference between these cases, at least at this point in the code. You might need to care about the list being changed in another thread, however, if it can become empty before (or while) executing createAmountText. But that's not something that was introduced by this refactoring.
TL;DR: using if (!substanceList.isEmpty()) { does practically the same thing, and is clearer to read.
The only difference between the first and the second approach is that the first approach performs a redundant check. nothing else.
Thus, you'd rather avoid the redundant check and go with the second approach.
Actually, you can read the source code downloaded in the JDK:
/**
* Returns <tt>true</tt> if this list contains no elements.
*
* #return <tt>true</tt> if this list contains no elements
*/
public boolean isEmpty() {
return size == 0;
}
I think that this settles all the queries.
Implementation of isEmpty() in AbstractCollection is as follows:
public boolean isEmpty() {
return size() == 0;
}
So you can safely assume that !list.isEmpty() is equivalent to list.size() > 0.
As for "what is better code", if you want to check if the list is empty or not, isEmpty() is definitely more expressive.
Subclasses might also override isEmpty() from AbstractCollection and implement in more efficient manner than size() == 0. So (purely theoretically) isEmpty() might be more efficient.
The javadocs for Collection.size() and Collection.isEmpty() say:
boolean isEmpty()
Returns true if this collection contains no elements.
int size()
Returns the number of elements in this collection
Since "contains no elements" implies that the number of elements in the collection is zero, it follows that list.isEmpty() and list.size() == 0 will evaluate to the same value.
I want to some explanation of above code
The second version is correct. The first version looks like it was written either by an automatic code generator, or a programmer who doesn't really understand Java. There is no good reason to write the code that way.
(Note: if some other thread could be concurrently modifying the list, then both versions are problematic unless there is proper synchronization. If the list operations are not synchronized then may be memory hazards. But in the first version, there is also the possibility of a race condition ... where the list appears be empty and have a non-zero size!)
and want to know second way may be caused some error.
It won't.
Incidentally list.isEmpty() is preferable to list.size() == 0 for a couple of reasons:
It is more concise (fewer characters).
It expresses the intent of your code more precisely.
It may be more efficient. Some collection implementations may need to count the elements in the collection to compute the size. That may be an O(N) operation, and could other undesirable effects. For example, if a collection is a lazy list that only gets reified as you iterate the elements, then calling size() may result in excessive memory use.
Yes, it can be refactored as you did. The issue with both approaches is that you would do the check every time you want to call the method createAmountText on a List. This means you would be repeating the logic, a better way would be to use DRY (don't Repeat Yourself) principle and factor these checks into your method.
So your method's body should encapsulated by this check.
It should look like:
<access modifier> String createAmountText(List substanceList){
if(substanceList != null && !substanceList.isEmpty()){
<The methods logic>
}
return null;
}
Sure - the two methods can be used to express the same thing.
But worth adding here: going for size() > 0 is somehow a more direct violation of the Tell, don't ask principle: you access an "implementation detail", to then make a decision based on that.
In that sense, isEmpty() should be your preferred choice here!
Of course, you are still violating TDA when using isEmpty() - because you are again fetching status from some object to then make a decision on it.
So the really best choice would be to write code that doesn't need at all to make such a query to internal state of your collection to then drive decisions on it. Instead, simply make sure that createAmountText() properly deals with you passing in an empty list! Why should users of this list, or of that method need to care whether the list is empty or not?!
Long story short: maybe that is "over thinking" here - but again: not using these methods would lead you to write less code! And that is always an indication of a good idea.
So, I have this code, which is just the way I solved an exercise that was given to me, which consisted of creating a recursive function that received a number, and then gave you the sum of 1, all the numbers in between, and your number. I know I made it sound confusing, but here's an example:
If I inserted the number 5, then the returned value would have to be 15, because: 1+2+3+4+5 = 15.
public class Exercise {
public static void main(String[] args) {
int returnedValue = addNumbers(6);
System.out.print(returnedValue);
}
public static int addNumbers(int value) {
if (value == 1) return value;
return value = value + addNumbers(value-1);
}
}
Technically speaking, my code works just fine, but I still don't get why Eclipse made me write two returns, that's all I would like to know.
Is there a way I could only write "return" once?
Sure, you can write it with just one return:
public static int addNumbers(int value) {
if (value > 1) {
value += addNumbers(value - 1);
}
return value;
}
As you can see, it's done by having some variable retain the running result until you get to the end. In this case I was able to do it in-place in value, in other cases you may need to create a local variable, but the idea of storing your intermediate result somewhere until you get to the return point is a general one.
There should be two returns. Your first return says
if at 1: stop recurstion
and the second one says
continue recursion by returning my value plus computing the value less than me
You could combine them by using a ternary:
return value == 1 ? value : value + addNumbers(value - 1)
But it is not as readable.
Recursive funtions like
Fibbonacci's sequence
Fractals
Etc.
Use themselves multiple times because they contain themselves.
Feel free to correct me if I'm wrong, but I don't think there is a way to eliminate one of those returns unless you decide to put a variable outside of the method or change the method from being recursive.
In java, a method that returns a value, MUST return a value at some point, no matter what code inside of it does. The reason eclipse requires you to add the second return, is because the first return is only run if your if statement evaluates to true. If you didn't have the second return, and that if statement did not end up being true, java would not be able to leave that method, and would have no idea what to do, thus, eclipse will require you to add a return statement after that if statement.
These types of errors are called checked errors or compile time errors. This means that eclipse literally can not convert your code into a runnable file, because it does not know how; there is a syntax error, or you are missing a return, etc.
Recursive functions always have at least 2 paths, the normal ones that will recurse and the "end" paths that just return (Usually a constant).
You could, however, do something like this:
public static int addNumbers(int value) {
if (value != 1)
value = value + addNumbers(value-1);
return value;
}
But I can't say I think it's much better (Some people get as annoyed at modifying parameters as they do at multiple returns). You could, of course, create a new variable and set it to one value or the other, but then someone would get upset because you used too many lines of code and an unnecessary variable. Welcome to programming :) Your original code is probably as good as you're likely to get.
As for why "Eclipse" did that to you, it's actually Java--Java is better than most languages at making sure you didn't do something clearly wrong as soon as possible (In this case while you are typing instead of waiting for you to compile). It detected that one branch of your if returned a value and the other did not--which is clearly wrong.
Java is also very explicit forcing you to use a "return" statement where another language might let you get away with less. In Groovy You'd be tempted to eliminate the return and write something like:
def addNumbers(value){value + (value-1?0:addNumbers(value-1))}
just for fun but I certainly wouldn't call THAT more readable! Java just figures it's better to force you to be explicit in most cases.
From the wikipedia on recursion:
In mathematics and computer science, a class of objects or methods
exhibit recursive behavior when they can be defined by two properties:
A simple base case (or cases)—a terminating scenario that does not use recursion to produce an answer
A set of rules that reduce all other cases toward the base case
There are two returns because you have to handle the two cases above. In your example:
The base case is value == 1.
The case to reduce all other cases toward the base case is value + addNumbers(value-1);.
Source: https://en.wikipedia.org/wiki/Recursion#Formal_definitions
Of course there are other ways to write this, including some that do not require multiple returns, but in general multiple returns are a clear and normal way to express recursion because of the way recursion naturally falls into multiple cases.
Like the robots of Asimov, all recursive algorithms must obey three important laws:
A recursive algorithm must have a base case.
A recursive algorithm must change its state and move toward the base case.
A recursive algorithm must call itself, recursively.
Your if (value == 1) return value; return statement is the base case. That's when the recursion(calling itself) stops. When a function call happen, the compiler pushes the current state to stack then make the call. So, when that call has returned some value, it pulls the value from stack, makes calculation and return the result to upper level. That's why the other return statement is for.
Think of this like breaking up your problem:
addNumbers(3) = 3 + addNumbers(2) (this is returned by second one)
-> 2 + addNumbers(1) (this is returned by second one)
-> 1 (this is returned by base case)
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;
Someone designed code that relied on full data; the XML always had every element. The data source is now sending sparse XML; if it would have been empty before, it's missing now. So, it's time to refactor while fixing bugs.
There's 100+ lines of code like this:
functionDoSomething(foo, bar, getRoot().getChild("1").getChild("A").
getChild("oo").getContent());
Except now, getChild("A") might return null. Or any of the getChild(xxx) methods might.
As one additional twist, instead of getChild(), there are actually four separate methods, which can only occur in certain orders. Someone suggested a varargs call, which isn't a bad idea, but won't work as cleanly as I might like.
What's the quickest way to clean this one up? The best? "try/catch" around every line was suggested, but man, that's ugly. Breaking out the third argument to the above method into it's own function could work... but that would entail 100+ new methods, which feels ugly, albeit less so.
The number of getChild(xxx) calls is somewhere between six and ten per line, with no fixed depth. There's also no possible way to get a correct DTD for this; things will be added later without a prior heads up, and where I'd prefer a warning in the logs when that happens, extra lines in the XML need to be handled gracefully.
Ideas?
getChild() is a convenience method, actually. The cleanest way I have in mind is to have the convenience methods return a valid Child object, but have that "empty" Child's getContent() always return "".
Please consider using XPATH instead of this mess.
What you described (returning a special child object) is a form of the NullObject pattern, which is probably the best solution here.
The solution is to use a DTD file for XML. It validates your XML file so getChild("A") won't return null when A is mandatory.
How about:
private Content getChildContent(Node root, String... path) {
Node target = root;
for ( String pathElement : path ) {
Node child = target.getChild(pathElement);
if ( child == null )
return null; // or whatever you should do
target = child;
}
return target.getContent();
}
to be used as
functionDoSomething(foo, bar, getChildContent(root, "1", "A", "oo"));
Your problem could be a design problem: Law of Demeter.
If not you can use something like an Option type changing the return type of getChild to Option<Node>:
for(Node r : getRoot())
for(Node c1 : r.getChild("1"))
for(Node c2: c1.getChild("A"))
return c2.getChild("oo")
This works because Option implements Iterable it will abort when a return value is not defined. This is similary to Scala where it can be expressed in a single for expression.
One additional advantage is that you can define interfaces that will never return a null value. With an Option type you can state in the interface definition that the return value may be undefined and the client can decide how to handle this.
If it always drills down to roughly the same same level, you can probably refactor the code using Eclipse, for example, and it'll automatically change every line that looks the same.
That way you can modify the method to be smarter, rather than modifying each line individually