JSqlParser - Pretty print where clause - java

I have started to use JSqlParser, i can parse a Where clause but i don't manage to go further with it.
JSqlParser github link
Indeed, i have tried to Override visit methods but don't understand how to reach my goal.
Let's say i have: (a=1 AND (b=2 OR (c=3 AND d=4))) OR e=2 as input and i would like as output:
-> a=1
-> AND
--> b=2
--> OR
---> c=3
---> AND
---> d=4
-> OR
-> e=5
My final goal is not a pretty print, but to understand how to know the current depth of the print at a given state. In order to dig in the tree as i want.
I have started a piece of code, parsing the where clause:
Expression expr = CCJSqlParserUtil.parseCondExpression("(a=1 AND (b=2 OR >(c=3 AND d=4))) OR e=2");
expr.accept(new ExpressionVisitorAdapter() {
#Override
public void visit(ExpressionClassToChoose expr) {
some code here...
}
});
Could you show me the way to start this kind of thing? Do i have to work with visit methods or am i wrong?
Thanks !

The visitor way is as always one way to go. If you want to get the parenthesis depth, you could stick with:
public void visit(Parenthesis parenthesis)
To get the ouput you want, is a little bit trickier. I implemented a simple example only taking ANDs and ORs into account. I do not use the ExpressionVisitorAdapter, but the ExpressionDeParser which is responsible for Expression printing. This way you can modify the generated output to your needs.
public static void main(String args[]) throws JSQLParserException {
Expression expr = CCJSqlParserUtil.parseCondExpression("(a=1 AND (b=2 OR (c=3 AND d=4))) OR e=2");
StringBuilder b = new StringBuilder();
expr.accept(new ExpressionDeParser(null, b) {
int depth = 0;
#Override
public void visit(Parenthesis parenthesis) {
if (parenthesis.isNot()) {
getBuffer().append("NOT");
}
depth++;
parenthesis.getExpression().accept(this);
depth--;
}
#Override
public void visit(OrExpression orExpression) {
visitBinaryExpr(orExpression, "OR");
}
#Override
public void visit(AndExpression andExpression) {
visitBinaryExpr(andExpression, "AND");
}
private void visitBinaryExpr(BinaryExpression expr, String operator) {
if (expr.isNot()) {
getBuffer().append("NOT");
}
if (!(expr.getLeftExpression() instanceof OrExpression)
&& !(expr.getLeftExpression() instanceof AndExpression)
&& !(expr.getLeftExpression() instanceof Parenthesis)) {
getBuffer().append(StringUtils.repeat("-", depth)).append(">");
}
expr.getLeftExpression().accept(this);
getBuffer().append("\n").append(StringUtils.repeat("-", depth)).append(">");
getBuffer().append(operator).append("\n");
if (!(expr.getRightExpression() instanceof OrExpression)
&& !(expr.getRightExpression() instanceof AndExpression)
&& !(expr.getRightExpression() instanceof Parenthesis)) {
getBuffer().append(StringUtils.repeat("-", depth)).append(">");
}
expr.getRightExpression().accept(this);
}
});
System.out.println(b);
}
As you can see, the parenthesis visitor changes the depth. The hard part is within visitBinaryExpression. The complex instanceof logic derives from using the And/OrExpression for output. Since for one text line multiple calls to visitBinaryExpression could happen, the indent has to be done from the most outer part.
If you would like to improve the printing of an JSqlParser parsed statement your updates should go to the deparsers.

Related

Performance vs Slightly Cleaner Code: checking attribute before vs during loop

I am adding some changes to existing code and noticed that it could possibly be optimized by checking a condition before hand, however doing so does make the code as clean.
The original code was something like this:
private void changeProperties(String a, String b, Document doc) {
if(!isEmptyOrNull(a)) {
doc.setA(a);
}
if(!isEmptyOrNull(b)){
doc.setB(b);
}
saveDocument(doc);
}
And then I added a method would simply take in a list and call the above method, like so
private void updatePropertiesForDocuments(List<Document> docs, String a, String b) {
docs.forEach(doc -> changeProperties(a, b, doc));
}
I then realized that, in the new functionality, that the attributes 'a' and 'b' will always be the same for each document. With this information, I thought that it is pretty pointless to check if 'a' and 'b' are null or empty for every single document (esepcially if the list can be quite large, such as 100,000+).
So then I thought it would be a better idea to just do the null checks before entering the loop like so:
private void updatePropertiesForDocuments(List<Document> docs, String a, String b) {
boolean isAMissing = isEmptyOrNull(a);
boolean isBMissing = isEmptyOrNull(b);
if(!isAMissing && !isBMissing) {
docs.forEach(doc -> {
doc.setA(a);
doc.setB(b);
saveDocument(doc);
});
} else if(!isBMissing) {
docs.forEach(doc -> {
doc.setB(b);
saveDocument(doc);
});
} else if(!isAMissing) {
docs.forEach(doc -> {
doc.setA(a);
saveDocument(doc);
});
}
}
I would like to know, if the size of the documents is large (100,000+), will there be a noticible difference in performance or is there some 'under the hood' optimization that the JVM does that would make it pointless to make this change?

Can I use the Conditional Operators in a non-assignment situation in JAVA?

In case of assignment the situation is simple,
result = testCondition ? value1 : value2;
But what if I want to use it instead of an if statement?
for instance in a logging situation:
logger.shouldDebbug ? logger.log("logging") : (what to do if not?);
In the case I don't what to do anything in the case of false, can I still use this Operator?
Yes you can if you wrap them in a returning function, but no you shouldn't.
In your example of the logger, let your logger output to void, discard the input when debugging isn't enabled.
You do not want to riddle your code with all these logging checks.
Perform a check as least and as central as possible.
Either have a check in the logger.log function if debugging is enabled, or replace the logger with a dummy mock that does nothing except accept input and immediately discard it.
If you use standard logging frameworks like log4j you can set debugging levels, where you show only info or more serious, only warnings or more serious, only errors or more serious.
The same goes for other "quick" checks. If you find yourself using a certain pattern a lot, write a utility class for it with a static method if need be, so you have one place, where you have to change stuff, instead of 200 code points that you have to update when going to production.
You could use it if you insist, by defining a meaningless variable and take advantage of the functions' side-effects, but that's not a very good coding habit. It's purely a work-around.
For example:
public static boolean test() {
return 1>0;
}
public static int success() {
System.out.println("true");
return 0; // has no meaning whatsoever
}
public static int fail() {
System.out.println("false");
return 0; // has no meaning whatsoever
}
public static void main(String[] args) {
int meaningless = test() ? success() : fail();
}
Everything has been explained in comments, so I will put here only some idea:
public class Ternary {
private final boolean condition;
private Ternary(boolean condition) { this.condition = condition; }
public static Ternary of(boolean condition) { return new Ternary(condition); }
public Ternary onTrue(Runnable r) { if (condition) { r.run(); } return this; }
public Ternary onFalse(Runnable r) { if (!condition) { r.run(); } return this; }
}
Example of usage:
Ternary.of(o != null).onTrue(() -> doSomething()).onFalse(() -> doSomethingElse());
But simplier would be to write:
if (o != null) { doSomething(); } else { doSomethingElse(); }

Use Java lambda instead of 'if else'

With Java 8, I have this code:
if(element.exist()){
// Do something
}
I want to convert to lambda style,
element.ifExist(el -> {
// Do something
});
with an ifExist method like this:
public void ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
}
}
But now I have else cases to call:
element.ifExist(el -> {
// Do something
}).ifNotExist(el -> {
// Do something
});
I can write a similar ifNotExist, and I want they are mutually exclusive (if the exist condition is true, there is no need to check ifNotExist, because sometimes, the exist() method takes so much workload to check), but I always have to check two times. How can I avoid that?
Maybe the "exist" word make someone misunderstand my idea. You can imagine that I also need some methods:
ifVisible()
ifEmpty()
ifHasAttribute()
Many people said that this is bad idea, but:
In Java 8 we can use lambda forEach instead of a traditional for loop. In programming for and if are two basic flow controls. If we can use lambda for a for loop, why is using lambda for if bad idea?
for (Element element : list) {
element.doSomething();
}
list.forEach(Element::doSomething);
In Java 8, there's Optional with ifPresent, similar to my idea of ifExist:
Optional<Elem> element = ...
element.ifPresent(el -> System.out.println("Present " + el);
And about code maintenance and readability, what do you think if I have the following code with many repeating simple if clauses?
if (e0.exist()) {
e0.actionA();
} else {
e0.actionB();
}
if (e1.exist()) {
e0.actionC();
}
if (e2.exist()) {
e2.actionD();
}
if (e3.exist()) {
e3.actionB();
}
Compare to:
e0.ifExist(Element::actionA).ifNotExist(Element::actionB);
e1.ifExist(Element::actionC);
e2.ifExist(Element::actionD);
e3.ifExist(Element::actionB);
Which is better? And, oops, do you notice that in the traditional if clause code, there's a mistake in:
if (e1.exist()) {
e0.actionC(); // Actually e1
}
I think if we use lambda, we can avoid this mistake!
As it almost but not really matches Optional, maybe you might reconsider the logic:
Java 8 has a limited expressiveness:
Optional<Elem> element = ...
element.ifPresent(el -> System.out.println("Present " + el);
System.out.println(element.orElse(DEFAULT_ELEM));
Here the map might restrict the view on the element:
element.map(el -> el.mySpecialView()).ifPresent(System.out::println);
Java 9:
element.ifPresentOrElse(el -> System.out.println("Present " + el,
() -> System.out.println("Not present"));
In general the two branches are asymmetric.
It's called a 'fluent interface'. Simply change the return type and return this; to allow you to chain the methods:
public MyClass ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
}
return this;
}
public MyClass ifNotExist(Consumer<Element> consumer) {
if (!exist()) {
consumer.accept(this);
}
return this;
}
You could get a bit fancier and return an intermediate type:
interface Else<T>
{
public void otherwise(Consumer<T> consumer); // 'else' is a keyword
}
class DefaultElse<T> implements Else<T>
{
private final T item;
DefaultElse(final T item) { this.item = item; }
public void otherwise(Consumer<T> consumer)
{
consumer.accept(item);
}
}
class NoopElse<T> implements Else<T>
{
public void otherwise(Consumer<T> consumer) { }
}
public Else<MyClass> ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
return new NoopElse<>();
}
return new DefaultElse<>(this);
}
Sample usage:
element.ifExist(el -> {
//do something
})
.otherwise(el -> {
//do something else
});
You can use a single method that takes two consumers:
public void ifExistOrElse(Consumer<Element> ifExist, Consumer<Element> orElse) {
if (exist()) {
ifExist.accept(this);
} else {
orElse.accept(this);
}
}
Then call it with:
element.ifExistOrElse(
el -> {
// Do something
},
el -> {
// Do something else
});
The problem
(1) You seem to mix up different aspects - control flow and domain logic.
element.ifExist(() -> { ... }).otherElementMethod();
^ ^
control flow method business logic method
(2) It is unclear how methods after a control flow method (like ifExist, ifNotExist) should behave. Should they be always executed or be called only under the condition (similar to ifExist)?
(3) The name ifExist implies a terminal operation, so there is nothing to return - void. A good example is void ifPresent(Consumer) from Optional.
The solution
I would write a fully separated class that would be independent of any concrete class and any specific condition.
The interface is simple, and consists of two contextless control flow methods - ifTrue and ifFalse.
There can be a few ways to create a Condition object. I wrote a static factory method for your instance (e.g. element) and condition (e.g. Element::exist).
public class Condition<E> {
private final Predicate<E> condition;
private final E operand;
private Boolean result;
private Condition(E operand, Predicate<E> condition) {
this.condition = condition;
this.operand = operand;
}
public static <E> Condition<E> of(E element, Predicate<E> condition) {
return new Condition<>(element, condition);
}
public Condition<E> ifTrue(Consumer<E> consumer) {
if (result == null)
result = condition.test(operand);
if (result)
consumer.accept(operand);
return this;
}
public Condition<E> ifFalse(Consumer<E> consumer) {
if (result == null)
result = condition.test(operand);
if (!result)
consumer.accept(operand);
return this;
}
public E getOperand() {
return operand;
}
}
Moreover, we can integrate Condition into Element:
class Element {
...
public Condition<Element> formCondition(Predicate<Element> condition) {
return Condition.of(this, condition);
}
}
The pattern I am promoting is:
work with an Element;
obtain a Condition;
control the flow by the Condition;
switch back to the Element;
continue working with the Element.
The result
Obtaining a Condition by Condition.of:
Element element = new Element();
Condition.of(element, Element::exist)
.ifTrue(e -> { ... })
.ifFalse(e -> { ... })
.getOperand()
.otherElementMethod();
Obtaining a Condition by Element#formCondition:
Element element = new Element();
element.formCondition(Element::exist)
.ifTrue(e -> { ... })
.ifFalse(e -> { ... })
.getOperand()
.otherElementMethod();
Update 1:
For other test methods, the idea remains the same.
Element element = new Element();
element.formCondition(Element::isVisible);
element.formCondition(Element::isEmpty);
element.formCondition(e -> e.hasAttribute(ATTRIBUTE));
Update 2:
It is a good reason to rethink the code design. Neither of 2 snippets is great.
Imagine you need actionC within e0.exist(). How would the method reference Element::actionA be changed?
It would be turned back into a lambda:
e0.ifExist(e -> { e.actionA(); e.actionC(); });
unless you wrap actionA and actionC in a single method (which sounds awful):
e0.ifExist(Element::actionAAndC);
The lambda now is even less 'readable' then the if was.
e0.ifExist(e -> {
e0.actionA();
e0.actionC();
});
But how much effort would we make to do that? And how much effort will we put into maintaining it all?
if(e0.exist()) {
e0.actionA();
e0.actionC();
}
If you are performing a simple check on an object and then executing some statements based on the condition then one approach would be to have a Map with a Predicate as key and desired expression as value
for example.
Map<Predicate<Integer>,Supplier<String>> ruleMap = new LinkedHashMap <Predicate<Integer>,Supplier<String>>(){{
put((i)-> i<10,()->"Less than 10!");
put((i)-> i<100,()->"Less than 100!");
put((i)-> i<1000,()->"Less than 1000!");
}};
We could later stream the following Map to get the value when the Predicate returns true which could replace all the if/else code
ruleMap.keySet()
.stream()
.filter((keyCondition)->keyCondition.test(numItems,version))
.findFirst()
.ifPresent((e)-> System.out.print(ruleMap.get(e).get()));
Since we are using findFirst() it is equivalent to if/else if /else if ......

Modelling a regular expression parser with polymorphism

So, I'm doing a regular expression parser for school that creates a hierarchy of objects in charge of the matching. I decided to do it object oriented because it's easier for me to imagine an implementation of the grammar that way. So, these are my classes making up the regular expressions. It's all in Java, but I think you can follow along if you're proficient in any object oriented language.
The only operators we're required to implement is Union (+), Kleene-Star (*), Concatenation of expressions (ab or maybe (a+b)c) and of course the Parenthesis as illustrated in the example of Concatination. This is what I've implemented right now and I've got it to work like a charm with a bit of overhead in the main.
The parent class, Regexp.java
public abstract class Regexp {
//Print out the regular expression it's holding
//Used for debugging purposes
abstract public void print();
//Checks if the string matches the expression it's holding
abstract public Boolean match(String text);
//Adds a regular expression to be operated upon by the operators
abstract public void add(Regexp regexp);
/*
*To help the main with the overhead to help it decide which regexp will
*hold the other
*/
abstract public Boolean isEmpty();
}
There's the most simple regexp, Base.java, which holds a char and returns true if the string matches the char.
public class Base extends Regexp{
char c;
public Base(char c){
this.c = c;
}
public Base(){
c = null;
}
#Override
public void print() {
System.out.println(c);
}
//If the string is the char, return true
#Override
public Boolean match(String text) {
if(text.length() > 1) return false;
return text.startsWith(""+c);
}
//Not utilized, since base is only contained and cannot contain
#Override
public void add(Regexp regexp) {
}
#Override
public Boolean isEmpty() {
return c == null;
}
}
A parenthesis, Paren.java, to hold a regexp inside it. Nothing really fancy here, but illustrates how matching works.
public class Paren extends Regexp{
//Member variables: What it's holding and if it's holding something
private Regexp regexp;
Boolean empty;
//Parenthesis starts out empty
public Paren(){
empty = true;
}
//Unless you create it with something to hold
public Paren(Regexp regexp){
this.regexp = regexp;
empty = false;
}
//Print out what it's holding
#Override
public void print() {
regexp.print();
}
//Real simple; either what you're holding matches the string or it doesn't
#Override
public Boolean match(String text) {
return regexp.match(text);
}
//Pass something for it to hold, then it's not empty
#Override
public void add(Regexp regexp) {
this.regexp = regexp;
empty = false;
}
//Return if it's holding something
#Override
public Boolean isEmpty() {
return empty;
}
}
A Union.java, which is two regexps that can be matched. If one of them is matched, the whole Union is a match.
public class Union extends Regexp{
//Members
Regexp lhs;
Regexp rhs;
//Indicating if there's room to push more stuff in
private Boolean lhsEmpty;
private Boolean rhsEmpty;
public Union(){
lhsEmpty = true;
rhsEmpty = true;
}
//Can start out with something on the left side
public Union(Regexp lhs){
this.lhs = lhs;
lhsEmpty = false;
rhsEmpty = true;
}
//Or with both members set
public Union(Regexp lhs, Regexp rhs) {
this.lhs = lhs;
this.rhs = rhs;
lhsEmpty = false;
rhsEmpty = false;
}
//Some stuff to help me see the unions format when I'm debugging
#Override
public void print() {
System.out.println("(");
lhs.print();
System.out.println("union");
rhs.print();
System.out.println(")");
}
//If the string matches the left side or right side, it's a match
#Override
public Boolean match(String text) {
if(lhs.match(text) || rhs.match(text)) return true;
return false;
}
/*
*If the left side is not set, add the member there first
*If not, and right side is empty, add the member there
*If they're both full, merge it with the right side
*(This is a consequence of left-to-right parsing)
*/
#Override
public void add(Regexp regexp) {
if(lhsEmpty){
lhs = regexp;
lhsEmpty = false;
}else if(rhsEmpty){
rhs = regexp;
rhsEmpty = false;
}else{
rhs.add(regexp);
}
}
//If it's not full, it's empty
#Override
public Boolean isEmpty() {
return (lhsEmpty || rhsEmpty);
}
}
A concatenation, Concat.java, which is basically a list of regexps chained together. This one is complicated.
public class Concat extends Regexp{
/*
*The list of regexps is called product and the
*regexps inside called factors
*/
List<Regexp> product;
public Concat(){
product = new ArrayList<Regexp>();
}
public Concat(Regexp regexp){
product = new ArrayList<Regexp>();
pushRegexp(regexp);
}
public Concat(List<Regexp> product) {
this.product = product;
}
//Adding a new regexp pushes it into the list
public void pushRegexp(Regexp regexp){
product.add(regexp);
}
//Loops over and prints them
#Override
public void print() {
for(Regexp factor: product){
factor.print();
}
}
/*
*Builds up a substring approaching the input string.
*When it matches, it builds another substring from where it
*stopped. If the entire string has been pushed, it checks if
*there's an equal amount of matches and factors.
*/
#Override
public Boolean match(String text) {
ArrayList<Boolean> bools = new ArrayList<Boolean>();
int start = 0;
ListIterator<Regexp> itr = product.listIterator();
Regexp factor = itr.next();
for(int i = 0; i <= text.length(); i++){
String test = text.substring(start, i);
if(factor.match(test)){
start = i;
bools.add(true);
if(itr.hasNext())
factor = itr.next();
}
}
return (allTrue(bools) && (start == text.length()));
}
private Boolean allTrue(List<Boolean> bools){
return product.size() == bools.size();
}
#Override
public void add(Regexp regexp) {
pushRegexp(regexp);
}
#Override
public Boolean isEmpty() {
return product.isEmpty();
}
}
Again, I've gotten these to work to my satisfaction with my overhead, tokenization and all that good stuff. Now I want to introduce the Kleene-star operation. It matches on any number, even 0, of occurrences in the text. So, ba* would match b, ba, baa, baaa and so on while (ba)* would match on ba, baba, bababa and so on. Does it even look possible to extend my Regexp to this or do you see another way of solving this?
PS: There's getters, setter and all kinds of other support functions that I didn't write out, but this is mainly for you to get the point quickly of how these classes works.
You seem to be trying to use a fallback algorithm to do the parsing. That can work -- although it is easier to do with higher-order functions -- but it is far from the best way to parse regular expressions (by which I mean the things which are mathematically regular expressions, as opposed to the panoply of parsing languages implemented by "regular expression" libraries in various languages).
It's not the best way because the parsing time is not linear in the size of the string to be matched; in fact, it can be exponential. But to understand that, it's important to understand why your current implementation has a problem.
Consider the fairly simple regular expression (ab+a)(bb+a). That can match exactly four strings: abbb, aba, abb, aa. All of those strings start with a, so your concatenation algorithm will match the first concatenand ((ab+a)) at position 1, and proceed to try the second concatenand (bb+a). That will successfully match abb and aa, but it will fail on aba and abbb.
Now, suppose you modified the concatenation function to select the longest matching substring rather than the shortest one. In that case, the first subexpression would match ab in three of the possible strings (all but aa), and the match would fail in the case of abb.
In short, when you are matching a concatenation R·S, you need to do something like this:
Find some initial string which matches R
See if S matches the rest of the text
If not, repeat with another initial string which matches R
In the case of full regular expression matches, it doesn't matter which order we list matches for R, but usually we're trying to find the longest substring which matches a regular expression, so it is convenient to enumerate the possible matches from longest to shortest.
Doing that means that we need to be able to restart a match after a downstream failure, to find the "next match". That's not terribly complicated, but it definitely complicates the interface, because all of the compound regular expression operators need to "pass through" the failure to their children in order to find the next alternative. That is, the operator R+S might first find something which matches R. If asked for the next possibility, it first has to ask R if there is another string which it could match, before moving on to S. (And that's passing over the question of how to get + to list the matches in order by length.)
With such an implementation, it's easy to see how to implement the Kleene star (R*), and it is also easy to see why it can take exponential time. One possible implementation:
First, match as many R as possible.
If asked for another match: ask the last R for another match
If there are no more possibilities, drop the last R from the list, and ask what is now the last R for another match
If none of that worked, propose the empty string as a match
Fail
(This can be simplified with recursion: Match an R, then match an R*. For the next match, first try the next R*; failing that try the next R and the first following R*; when all else fails, try the empty string.)
Implementing that is an interesting programming exercise, so I encourage you to continue. But be aware that there are better algorithms. You might want to read Russ Cox's interesting essays on regular expression matching.

is there a equivalent of StringBuilder for boolean in java?

I want my custom functions to modify / toggle a boolean variable. Let's say that I have code like
if (OK2continue) { findANDclick(new String[]{"id", "menuButton"});}
if (OK2continue) { findANDclick(new String[]{"src", ".*homeicon_calendar.*"}); }
if (OK2continue) { findANDclick(new String[]{"src", ".*cycle_templates.*"});
I want to make sure that the flow of execution stops once any of the findANDclick functions toggles the variable OK2continue
I managed my functions to modify a String variable using StringBuilder.
Can I do the same for boolean type of variable?
I can't say it is equivalent. But using MutableBoolean offers you a mutable boolean wrapper, similar to the concept of StringBuilder a mutable sequence of characters. See this JavaDoc for details.
Push this code into its own method, and use a return:
if (findANDclick(new String[]{"id", "menuButton"})) return;
if (findANDclick(new String[]{"src", ".*homeicon_calendar.*"})) return;
if (findANDclick(new String[]{"src", ".*cycle_templates.*"})) return;
Given that all your method calls are the same, you could also use a loop:
String[][] buttons = {
{"id", "menuButton"},
{"src", ".*homeicon_calendar.*"},
{"src", ".*cycle_templates.*"},
};
for (String[] button: buttons) {
if (findANDclick(button)) return;
}
You might or might not find that more readable.
You need to clarify your reference to your usage of StringBuilder.
Assuming:
You pass reference of the StringBuilder to your method. String is changed in method. If this the case, then see #Gordon Murray Dent's answer.
Your boolean flag is visible in the method but is not passed. A simple Boolean will do.
package sof_6232851;
public class SideEffectingMethod {
static Boolean flag = false;
public static void main(String[] args) {
flag = true;
System.out.format ("flag is %b\n", flag);
clickMe();
System.out.format ("flag is %b\n", flag);
}
/** this method side-effects instance variable flag */
public static void clickMe () {
flag = !flag;
}
}
[edit list item #2 to reply to OP comment]:
Note that #2 is not really recommended. You mention your desire for "readable" code. Side-effecting methods works against that goal.
public class ReturnValuesForFunAndProfit {
public static void main(String[] args) {
presentUI();
}
public static void presentUI() {
if(!clickMe("woof")) return;
if(!clickMe("meow")) return;
if(!clickMe("hello")) return;
}
public static boolean clickMe (String blah) {
// your logic here; this ex. always returns true
return true;
}
}
Well, the concept of StringBuilder is to create a mutable and extendable String wrapper (meaning the string can be extended via append and the like :) ). You'd still have to pass it as a parameter to the method in order to modify it (or use a static var - not recommended).
Since boolean can't be extended, the only similarity would be the parameter to be mutable. So you can use MutableBoolean as Gordon suggested, but you'd still have to pass it.
Another option would be to return a boolean from findANDclick(...) and use the boolean opperators like: findAndClick(...) || findAndClick(...) || findAndClick(...) which would only execute the next findAndClick(...) if the previous returned false.
Since that option is somewhat hard to maintain, especially since you might have side effects in findAndClick(...) as well as being quite static and hard to read if you have more calls in there, you might want to use a list of function objects:
class FindAndClickExecutor {
public FindAndClickExecutor(String[] params) {...}
public boolean findAndClick() {...}
}
List<FindAndClickExecutor> faces = ...; //initialize appropriately
for( FindAndClickExecutor face : faces ) {
boolean ok2continue = face.findAndClick();
if( !ok2continue ) {
break;
}
}
Edit: since there seem to be other methods as well, you might use a more general list:
interface Executor {
boolean execute();
}
class FindAndClickExecutor implements Executor {
public boolean execute() {} // findAndClick code here, set parameters using constructor
}
class FindAndSelectOptionExecutor implements Executor {
public boolean execute() {} // findAndSelectOption code here
}
List<Executor> testCase1Sequence = ...; //initialize test case 1
List<Executor> testCase2Sequence = ...; //initialize test case 2
for( Executor ex : testCase1Sequence ) {
boolean ok2continue = ex.execute();
if( !ok2continue) {
break;
}
}
This example could also be expanded on, e.g. by using a more complex return value containing the continue flag and maybe more data (use interface here as well).
Edit 2: you could also use some scripting to define and the builder pattern to generate the list of executors for each test case.

Categories

Resources