I was just creating this specific but I was a little confused on documenting this. Am just stuck on explaining what the last couple of lines do :
class MyVerifier extends InputVerifier {
public boolean verify(JComponent input) {
if (input==id) {
return validId();
}
else if (input==name) {
return validName();
}
return false;
}
public boolean validId() {
boolean status;
String theID = id.getText();
Pattern pattern = Pattern.compile("\\d{8}");
Matcher matcher = pattern.matcher(theID);
if (matcher.matches()) {
status = true;
}
else {
status = false;
}
return status;
}
public boolean validName() {
boolean status;
String theName = name.getText();
Pattern pattern = Pattern.compile("[A-za-z0-9 ]+");
Matcher matcher = pattern.matcher(theName);
if (matcher.matches()) {
status = true;
}
else {
status = false;
}
return status;
}
}
COULD YOU EXPLAIN THESE SPECIFIC LINES HERE ONE BY ONE ?
/**
* #param o the object corresponding to the user's selection
*/
#Override
public void tell(Object o) { -- Where has this come from ?
deptCode.setText(o.toString());
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == submit) {
MyVerifier test = new MyVerifier();
if (Staff.getStaff(id.getText()) == null && test.verify(id) &&
test.verify(name)) {
System.out.println("YAY");-- What is this doing
}
else if (!(Staff.getStaff(id.getText()) == null)) {
String errorMessage = "ID EXISTS: " + Staff.getStaff(id.getText()).toString(); -- What is this doing
JOptionPane.showMessageDialog(theFrame, errorMessage, "Error",
JOptionPane.WARNING_MESSAGE);-- What is this doing
}
else {
System.out.println("Woops.");
}
}
else if (e.getSource() == clear) {
id.setText(null);
deptCode.setText(null);
name.setText(null);
}
}
public static void main(String[] args) {
Registration test = new Registration();
}
}
Now that you understand what you're trying to accomplish with this program, start from a clean slate (using your first attempt as an example if necessary). It's often easier to start over than to fix a program.
It appears that your public void tell(Object o) method is setting a String with the value of the object passed. Because you haven't shown us what your using it for, though, it's impossible for us to know for sure. On the other hand, your other problems are fairly clear:
System.out.println("YAY");
It appears that Staff.getStaff(id.getText) is checking either a String or a text file for a list of names and id's. This statement prints "YAY" only if there hasn't previously been created a staff member with the provided id and name. But since you also haven't shown us where those variables are, this is only my best guess.
JOptionPane.showMessageDialog(theFrame, errorMessage, "Error", JOptionPane.WARNING_MESSAGE);
This displays a JOptionPane warning message if there is already a staff member with the given id or name. Obviously, you cannot create an account that someone else has, so this JOptionPane displays an error message if this is, indeed, the case.
Related
I need to write the logic with many conditions(up to 30 conditions) in one set of rule with many if else conditions and it could end in between or after all the conditions.
Here is the sample code I have tried with some possible scenario. This gives me result but doesn't look good and any minor miss in one condition would take forever to track.
What I have tried so far is, Take out common conditions and refactored to some methods. Tried creating interface with conditions and various set would implement it.
If you have any suggestion to design this, would help me. Not looking for detailed solution but even a hint would be great.
private Boolean RunCondition(Input input) {
Boolean ret=false;
//First if
if(input.a.equals("v1")){
//Somelogic1();
//Second if
if(input.b.equals("v2"))
//Third if
if(input.c >1)
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(input.d.equals("Z1"))
System.out.println("Passed 1");
// Fourth Else
else{
System.out.println("Failed at fourth");
}
//Third Else
else{
if(input.aa.equals("v2"))
System.out.println("Failed at third");
}
//Second Else
else{
if(input.bb.equals("v2"))
System.out.println("Failed at second");
}
}
//First Else
else{
if(input.cc.equals("v2"))
System.out.println("Failed aat first");
}
return ret;
}
public class Input {
String a;
String b;
int c;
String d;
String e;
String aa;
String bb;
String cc;
String dd;
String ee;
}
The flow is complicated because you have a normal flow, plus many possible exception flows when some of the values are exceptional (e.g. invalid).
This is a perfect candidate to be handled using a try/catch/finally block.
Your program can be rewritten into following:
private Boolean RunCondition(Input input) {
Boolean ret=false;
try {
//First if
if(!input.a.equals("v1")) {
throw new ValidationException("Failed aat first");
}
//Somelogic1();
//Second if
if(!input.b.equals("v2")) {
throw new ValidationException("Failed at second");
}
//Somelogic2()
//Third if
if(input.c<=1) {
throw new ValidationException("Failed at third");
}
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(!input.d.equals("Z1")) {
throw new ValidationException("Failed at fourth");
}
System.out.println("Passed 1");
} catch (ValidationException e) {
System.out.println(e.getMessage());
}
return ret;
}
Where you can define your own ValidationException (like below), or you can reuse some of the existing standard exception such as RuntimeException
class ValidationException extends RuntimeException {
public ValidationException(String arg0) {
super(arg0);
// TODO Auto-generated constructor stub
}
/**
*
*/
private static final long serialVersionUID = 1L;
}
You can read more about this in
https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html
Make a separate class for the condition:
package com.foo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App
{
static class Condition<T> {
final int idx;
final T compareValue;
public Condition(final int idx, final T compareValue) {
this.idx = idx;
this.compareValue = compareValue;
}
boolean satisfies(final T other) {
return other.equals(compareValue);
}
int getIdx() {
return idx;
}
}
public static void main( String[] args )
{
final List<Condition<String>> conditions = new ArrayList<Condition<String>>();
conditions.add(new Condition<String>(1, "v1"));
conditions.add(new Condition<String>(2, "v2"));
final List<String> inputs = new ArrayList<String>(Arrays.asList("v1", "xyz"));
boolean ret = true;
for (int i = 0; i < inputs.size(); i++) {
if (!conditions.get(i).satisfies(inputs.get(i)))
{
System.out.println("failed at " + conditions.get(i).getIdx());
ret = false;
break;
}
}
System.out.println("ret=" + ret);
}
}
#leeyuiwah's answer has a clear structure of the conditional logic, but exceptions aren't the right tool for the job here.
You shouldn't use exceptions to cope with non-exceptional conditions. For one thing, exceptions are really expensive to construct, because you have to walk all the way up the call stack to construct the stack trace; but you don't need the stack trace at all.
Check out Effective Java 2nd Ed Item 57: "Use exceptions only for exceptional conditions" for a detailed discussion of why you shouldn't use exceptions like this.
A simpler option is to define a little helper method:
private static boolean printAndReturnFalse(String message) {
System.out.println(message);
return false;
}
Then:
if(!input.a.equals("v1")) {
return printAndReturnFalse("Failed aat first");
}
// etc.
which I think is a simpler; and it'll be a lot faster.
Think of each rule check as an object, or as a Strategy that returns whether or not the rule passes. Each check should implement the same IRuleCheck interface and return a RuleCheckResult, which indicates if the check passed or the reason for failure.
public interface IRuleCheck
{
public RuleCheckResult Check(Input input);
public String Name();
}
public class RuleCheckResult
{
private String _errorMessage;
public RuleCheckResult(){}//All Good
public RuleCheckResult(String errorMessage)
{
_errorMessage = errorMessage;
}
public string ErrorMessage()
{
return _errorMessage;
}
public Boolean Passed()
{
return _errorMessage == null || _errorMessage.isEmpty();
}
}
public class CheckOne implements IRuleCheck
{
public RuleCheckResult Check(Input input)
{
if (input.d.equals("Z1"))
{
return new RuleCheckResult();//passed
}
return new RuleCheckResult("d did not equal z1");
}
public String Name();
}
Then you can simply build a list of rules and loop through them,
and either jump out when one fails, or compile a list of failures.
for (IRuleCheck check : checkList)
{
System.out.println("checking: " + check.Name());
RuleCheckResult result = check.Check(input);
if(!result.Passed())
{
System.out.println("FAILED: " + check.Name()+ " - " + result.ErrorMessage());
//either jump out and return result or add it to failure list to return later.
}
}
And the advantage of using the interface is that the checks can be as complicated or simple as necessary, and you can create arbitrary lists for checking any combination of rules in any order.
Clean code means for me: only one task for each methode and no nested loops.
When I got the following code, I asked myself, how can I avoid nested for loops and encapsulate them in methods.
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
for (Option option : getOptions(context)) {
for (Group group : getGroups()) {
if (option.getValue().equalsIgnoreCase(group.getName())) {
return group.getUser();
}
}
}
}
return "default";
}
My first solution was the following. The problem here is, the for loops are running until the end and do not break (return) when the value is found and set.
private String user = "default";
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
processOptions(context);
}
return this.user;
}
private void processOptions(FieldConfigScheme context){
for (Option option : getOptions(context)) {
processGroups(option);
}
}
private void processGroups(Option option){
for (Group group : getGroups()) {
setUser(option, group);
}
}
private void setUser(Option option, Group group){
if (option.getValue().equalsIgnoreCase(group.getName())) {
this.user = group.getUser();
}
}
so I wrote this code, which should be the same like the first:
private String user = "default";
private boolean isUserSet = false;
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
if(!isUserSet) processOptions(context);
else return this.user;
}
return this.user;
}
private void processOptions(FieldConfigScheme context){
for (Option option : getOptions(context)) {
if(!isUserSet) processGroups(option);
else return;
}
}
private void processGroups(Option option){
for (Group group : getGroups()) {
if(!isUserSet) setUser(option, group);
else return;
}
}
private void setUser(Option option, Group group){
if (option.getValue().equalsIgnoreCase(group.getName())) {
this.user = group.getUser();
isUserSet = true;
}
}
But then I asked myself, is this really better code? Is this more clean code? Yes, every method is only doing one thing. And yes, the code is better to read in my opinion. But from originally 12 lines compact code I now got 30 lines of code and one member variable more in the code. So is the first originally code better because it's more compact even with nested for loops?
What do you think? Which one is better? Or how can I write the code better?
Thanks in advance for your answers!
Instead of returning void, why not boolean?
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
if (processOptions(context)) {
break;
}
}
return this.user;
}
private boolean processOptions(FieldConfigScheme context){
for (Option option : getOptions(context)) {
if (processGroups(option)) {
return true;
}
}
return false;
}
private boolean processGroups(Option option){
for (Group group : getGroups()) {
if (option.getValue().equalsIgnoreCase(group.getName())) {
this.user = group.getUser();
return true;
}
}
return false;
}
T.B.H. I prefer the nested loops method. It looks clean, there is nothing more going on in the loop than to simply find something in a hierarchy and this is perfectly fine.
The use of extra function in this case is just bad. Imagine having to debug this code now, rather than focusing on one method which is doing this, you will have to look at all the extra ones you made.
Also this method doesn't seem to take any parameters which suggests that it actually only needs to do this check once and the rest of the time it should just return the same value. That just a guess, but if that was the case, then it makes your efforts to make it cleaner all the more unnecessary.
I have a class, LazyAuthor, that stores information about an author and can have a 'rival' (another object of the same class) set for it, and various methods cause them to interact with each other. The LazyAuthor class also relies on another class Book which stores details of the book's title, etc.
I am trying to set up a method rivalsLastTitle that returns the title (from the corresponding Book object) for the rival's last book. I have written this as:
public String rivalsLastTitle(){
return currentRival.getLastBook().getTitle();
}
where the corresponding methods I've called are
public Book getLastBook(){
return lastBook;
}
from the LazyAuthor class and
public String getTitle(){
return title;
}
from the Book class. currentRival is an object of the LazyAuthor class.
However this is returning a null value so clearly my syntax is wrong. I'm not sure how to write this code in order for it to return the title of the rival's lastBook object. I believe I may be overcomplicating the instruction for the return statement but I have seen multiple method calls like this work before.
Any help would be appreciated, I would be happy to share other parts of the code if that's useful. Thank you
edit: Here is the code for the whole LazyAuthor class. Apologies for length:
// fields (data members) go here
private int currentMoney, newMoney;
private String authorName, name;
private Book lastBook, bestBook, rLastBook, newBook, newLastBook,newBestBook, nextBook;
private LazyAuthor currentRival, newRival;
private boolean happy, jealous, lol;
// methods go here
public LazyAuthor(String name){
authorName = name;
currentMoney = 10000;
}
//set methods
public void setLastBook(Book newLastBook){
lastBook = newLastBook;
}
public void setBestBook(Book newBestBook){
bestBook = newBestBook;
}
public void setRival(LazyAuthor newRival){
newRival = currentRival;
}
public void setMoney(int newMoney){
newMoney = currentMoney;
}
public void setName(String name){
name = authorName;
}
//get methods
public Book getLastBook(){
return lastBook;
}
public Book getBestBook(){
return bestBook;
}
public int getMoney(){
return currentMoney;
}
public String getName(){
return authorName;
}
public LazyAuthor getRival(){
return currentRival;
}
// complex methods
public String lastTitle(){
return lastBook.getTitle();
}
public String bestTitle(){
return bestBook.getTitle();
}
public String rivalsLastTitle(){
rLastBook = currentRival.getLastBook();
return rLastBook.getTitle();
}
public boolean isHappy(){
// happy if last book written is their best OR they sold film rights for it
if(lastBook == bestBook || lastBook.filmRightsAreSold() == true) {
happy = true; }
else {
happy = false; }
return happy;
}
public boolean isJealous(){
// jealous if their rival's last book made more money, but isn't jealous if they managed to sell film rights for their last book
rLastBook = currentRival.getLastBook();
if(rLastBook.getValue() > lastBook.getValue() ){
jealous = true; }
else {
jealous = false;}
if(lastBook == bestBook || lastBook.filmRightsAreSold() == true) {
jealous = false; }
return jealous;
}
public boolean laughsAboutRival(){
// they laugh if their rival didn't sell film rights for their last book or if it made less than their own
rLastBook = currentRival.getLastBook();
if(rLastBook.filmRightsAreSold() == false || currentRival.getLastBook().getValue() < lastBook.getValue()) {
lol = true; }
else {
lol = false;}
return lol;
}
public void buyBackRightsOfLastBook(){
if(lastBook.filmRightsAreSold() == true && currentMoney >= lastBook.getBuyBackCost() ){
setMoney(currentMoney - lastBook.getValue() );
lastBook.buyBackRights(); }
}
public void writeNewBook(Book newBook){
// writes new book only if their last book wasn't their best, and they didn't sell the rights to it.
if(lastBook!=bestBook && lastBook.filmRightsAreSold() == false && currentMoney < lastBook.getValue() ){
lastBook = newBook;
currentMoney= currentMoney + lastBook.getValue();
}
}
edit 2: having just looked over the code again while editing this post, I seem to have assigned the labels in some of the set methods the wrong way around. I'm editing this now and will see if this fixes the null pointers.
edit 3: this seems to have worked, thank you all for the reassurance that my original syntax was correct and also for clarification on what a null value implies has gone wrong :)
The following code is designed to allow more natural assertions about the size of a stream.
Matcher<Stream> hasCount(int count) {
return new TypeSafeDiagnosingMatcher<Stream>() {
protected boolean matchesSafely(Stream stream, Description desc) {
long streamCount = stream.count();
if (streamCount == count) {
return true;
} else {
desc.appendText("count ").appendValue(streamCount);
return false;
}
}
public void describeTo(Description desc) {
desc.appendText("count ").appendValue(count);
}
};
}
This allows assertions such as:
assertThat(getWidgetStream(), hasCount(52));
It works fine when the assertion passes but when it fails (e.g. assertThat(Stream.empty(), hasCount(1));) it returns the error
"stream has already been operated upon or closed" rather than the expected description "expected: count <1> had: count <0>".
When I checked the source for TypeSafeDiagnosingMatcher I found that matchesSafely is called from both matches and describeMismatch. So Hamcrest is assuming matchesSafely is idempotent which mine isn't.
Is there a way around this problem?
One solution I've discovered is to store the result between invocations.
return new TypeSafeDiagnosingMatcher<Stream>() {
private Optional<Long> streamCount = Optional.empty();
protected boolean matchesSafely(Stream stream, Description desc) {
if (!streamCount.isPresent())
streamCount = Optional.of(stream.count());
if (streamCount.get() == count) {
return true;
} else {
desc.appendText("has count ").appendValue(streamCount.get().intValue());
return false;
}
}
};
This works but is not particularly elegant.
How can I make an option accept only some specified values like in the following example:
$ java -jar Mumu.jar -a foo
OK
$ java -jar Mumu.jar -a bar
OK
$ java -jar Mumu.jar -a foobar
foobar is not a valid value for -a
Since commons-cli doesn't support that directly, the simplest solution is probably to check the value of an option when you get it.
The other way can be to extend the Option class. At work we have made that:
public static class ChoiceOption extends Option {
private final String[] choices;
public ChoiceOption(
final String opt,
final String longOpt,
final boolean hasArg,
final String description,
final String... choices) throws IllegalArgumentException {
super(opt, longOpt, hasArg, description + ' ' + Arrays.toString(choices));
this.choices = choices;
}
public String getChoiceValue() throws RuntimeException {
final String value = super.getValue();
if (value == null) {
return value;
}
if (ArrayUtils.contains(choices, value)) {
return value;
}
throw new RuntimeException( value " + describe(this) + " should be one of " + Arrays.toString(choices));
}
#Override
public boolean equals(final Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
return new EqualsBuilder().appendSuper(super.equals(o))
.append(choices, ((ChoiceOption) o).choices)
.isEquals();
}
#Override
public int hashCode() {
return new ashCodeBuilder().appendSuper(super.hashCode()).append(choices).toHashCode();
}
}
I've wanted this kind of behaviour before, and never came across a way to do this with an already provided method. That's not to say it doesn't exist. A kind of lame way, is to add the code yourself such as:
private void checkSuitableValue(CommandLine line) {
if(line.hasOption("a")) {
String value = line.getOptionValue("a");
if("foo".equals(value)) {
println("OK");
} else if("bar".equals(value)) {
println("OK");
} else {
println(value + "is not a valid value for -a");
System.exit(1);
}
}
}
Obviously there would be nicer ways to do this than the long if/else, possibly with an enum, but that should be all you'd need. Also I've not compiled this, but I reckon it should work.
This example also does not make the "-a" switch mandatory, since that wasn't specified in the question.