I am working on a project in my Java class that is using multiple classes as well as GUI (not sure if that info is relevant). My group partner and I have come across an issue though. We have a Validator class, that should validate a "SSN" but we are continuously given the error:
java:146: error: incompatible types: double cannot be converted to boolean
if(Validator.isValidSSN(jTextFieldEmpSSN)){
Now obviously java:146 is the line. the code we have for each class is:
employeeUI class (the one showing the error):
private void jButtonEnterActionPerformed(java.awt.event.ActionEvent evt)
{
Employee e=new Employee();
if(Validator.isValidName(jTextFieldEmpFirst)){
if(Validator.isValidName(jTextFieldEmpLast)){
if(Validator.isValidEmail(jTextFieldEmpEmail)){
if(Validator.isValidSSN(jTextFieldEmpSSN)){
e.setFirstName(jTextFieldEmpFirst.getText());
e.setLastName(jTextFieldEmpLast.getText());
e.setEmailAdd(jTextFieldEmpEmail.getText());
e.setSSN(Integer.parseInt(jTextFieldEmpSSN.getText()));
}}}}
and the Validator class for isValidSSN is:
public static double isValidSSN(JTextField textfield)
{
double number = 0;
boolean inRange = false;
while(!inRange)
{
number = Double.parseDouble(textfield.getText());
if (number >= 100000000 && number <= 999999999)
{
inRange = true;
} else {}
}
return number;
}
We have been beating our head on how to fix this for quite some time, but are coming up at a loss. Are we missing something? we would greatly appreciate any help with this.
If I ask, "Is 123-45-6789" a valid SSN?" you wouldn't reply "123456789.0", would you? You'd give me a yes or a no. By returning double your method is doing the former. It's responding with a number instead of an answer to the question.
A good rule of thumb is that methods starting with is or has should return booleans. "Is this a valid SSN?" is a yes/no question, so isValidSSN should return the programming equivalent of yes/no.
public static boolean isValidSSN(JTextField textfield)
There are a couple of other design points here:
The loop isn't necessary. The SSN is either valid or it isn't.
A text field is not itself an SSN. It holds some text, and that text is the SSN. Rather than taking a text field and looking up the text in the field with getText(), it'd be better to have isValidSSN take the text directly. Let the caller extract the text from the text field.
In broader terms this is known as the single responsibility principle. Every method should ideally do just one thing.
Result:
public static boolean isValidSSN(String ssn) {
double number = Double.parseDouble(ssn);
if (number >= 100000000 && number <= 999999999) {
return true;
}
else {
return false;
}
}
P.S. If I don't mention it someone will surely comment that the if and else blocks aren't necessary; one can return the if result directly. They would be right, though I consider it a bit of an advanced trick. It would look like so:
public static boolean isValidSSN(String ssn) {
double number = Double.parseDouble(ssn);
return number >= 100000000 && number <= 999999999;
}
Related
I am making a number guessing game:
The computer generates a number inside an interval
I try to guess it and receive a reply whether it's higher/lower than my guess or equals to my guess and I've won
There is an interval in which I can guess, as well as a guess attempt limit
The trick is, however, that I need to implement another condition: each guess should "shrink" the interval in which I'm able to guess. For example: computer generates 50, I guess 25, computer replies "The random number is larger.". Now knowing that, I should not guess anything lower than 25 again, it's unreasonable. In case I guess i.e. 15, the computer should reply "The guess doesn't make sense.". I understand that I somehow need to save each guess value to a new variable, but nothing seems to work. I'm a beginner, please bear with the following code, I've tried a lot of things:
public String guess(int guess)
{
int lowerBound = 0;
int upperBound = 99;
Set<Integer> lowerGuesses = new TreeSet<>();
Set<Integer> higherGuesses = new TreeSet<>();
if (gameOver) {
return "The game is over.";
}
if (guess < 0 || guess > 99) {
return "The guess is out of bounds.";
}
if (guessCount < maxGuessCount) {
if (guess < secretNumber) {
if (lowerGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
else {
guessCount++;
lowerBound = guess;
lowerGuesses.add(guess);
return "The random number is larger.";
}
}
if (guess > secretNumber) {
if (higherGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
else {
guessCount++;
upperBound = guess;
higherGuesses.add(guess);
return "The random number is smaller.";
}
}
if (lowerGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
if (higherGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
}
if (guess < lowerBound || guess > upperBound) {
return "The guess doesn't make sense.";
}
if (guessCount == maxGuessCount) {
gameOver = true;
victorious = false;
return "Ran out of guess attempts.";
}
guessCount++;
gameOver = true;
victorious = true;
return "You won.";
}
Thank you in advance!
First, to avoid confusion, let's rename the method in order to make sure that its name is not an exact match with its parameter, so this is how it should look like:
public String makeGuess(int guess)
avoid naming different entities in the same name space with the exact same name (local variables being present in different methods or parameters having similar names with data members for the purpose of initialization are an exception). From now on, you will call the method as makeGuess(25), for example.
Now, to the actual problem. You have an incorrect assumption. You assume that you need to keep track of past intervals. That's not the case. You can just change the edges of the intervals. Also, your code is superfluous, I advise you to refactor it. Finally, you always initialize upper bounds, local bounds and higher and lower guesses as local variables, so they will never be kept track of. Instead of this, you need to perform the following simple measures in order to make this work:
Define the bounds and limit as data members
protected int lowerBound = 0;
protected int higherBound = 99;
protected int lb = 0;
protected int hb = 99;
protected int limit = 5;
protected int guessCount = 0;
protected int randomizedNumber; //Initialize this somewhere
Note that I have hard-coded some values. You might want to make this dynamic with initialization and stuff like that, but that's outside the scope of the answer. lowerBound, higherBound, limit are game settings. while lb, hb, guessCount represent the game state. You could separate this logic into another class, but for the sake of simplicity, even though I would program differently, I will leave them here in this case.
Have a method that initializes the game
public void initialize() {
lb = lowerBound;
hb = higherBound;
guessCount = 0;
}
So you separate your concern of game initialization from the outer logic of starting and maintaining a game.
Implement makeGuess in a simplistic way
public String makeGuess(int guess) {
if (++guessCount >= limit) return "The game is over.";
else if ((lb > guess) || (hb < guess)) return "The guess doesn't make sense";
else if (randomizedNumber == guess) return "You won.";
else if (guess < randomizedNumber) {
hb = guess;
return "The random number is smaller.";
} else {
lb = guess;
return "The random number is larger.";
}
}
NOTE: I dislike mixing up the logic with the output layer, the reason I did it in the method above was that you have mentioned you are a beginner and my intention is to make this answer understandable for the person who just begun programming and is very confused. For the purpose of actual solutions, you should return a state and in a different layer process that state and perform the console/UI operations you need. I will not go through the details now, as it would also be outside of scope, but for now, please have some success with the solution above, but THEN you should DEFINITELY look into how you need to code, because that is almost as important as making your code work.
Okay, I'm totally rewriting this question because this works and I want to know why it works.
Suppose I have a number, testNumber with a value of 567.
I want to know if the next two numbers (shouldPassTest and shouldFailTest) the same digits, but in different 10s places.
So here's the code:
int testNumber = 567;
int num1 = 5;
int num2 = 6;
int num3 = 7;
int shouldPassTest = 756;
int shouldFailTest = 777;
if(Integer.toString(shouldPassTest).matches("[5,6,7][5,6,7][5,6,7]")
{
//Do some cool stuff
}
if(Integer.toString(shouldFailTest).matches("[5,6,7][5,6,7][5,6,7]")
{
//Do some cool stuff
}
What happens when you run that, is that each digit is tested from the range of available digits (5, 6, and 7). Theoretically, shouldFailTest should actually pass the test seeing as how 7 matches one of my three criteria, albeit 3 times.
But what happens is that 777 returns false, when tested. This is precisely the result I wanted in my code, but I want to know why it happened. Does the matches method test to make sure that each number is only matched once?
Thanks!
This post was highly edited. After running my code, I found that the method does exactly what I want, but now I want to know why. Thanks.
I would use the following as regex is not a good solution to this problem:
public class Count {
private int value;
public Count() {
value=0;
}
void increment() {
value++;
}
void decrement() {
value--;
}
public int getValue() {
return value;
}
}
public static boolean isAnagram(int val1, int val2) {
Map<Character, Count> characterCountMap=new HashMap<>();
for(char c:Integer.toString(val1).toCharArray()) {
Count count=characterCountMap.get(c);
if(count==null) { count=new Count(); characterCountMap.put(c, count);}
count.increment();
}
for(char c:Integer.toString(val2).toCharArray()) {
Count count=characterCountMap.get(c);
if(count==null) { return false; }
else { count.decrement(); }
if(count.getValue()==0) {
characterCountMap.remove(c);
}
}
return characterCountMap.size()==0;
}
Please run:
System.out.println(Integer.toString(shouldFailTest).matches("[5,6,7][5,6,7][5,6,7]"));
to view the actual return value.
Theoretically, shouldFailTest should actually pass the test seeing as
how 7 matches one of my three criteria, albeit 3 times.
But what happens is that 777 returns false, when tested. This is
precisely the result I wanted in my code, but I want to know why it
happened. Does the matches method test to make sure that each number
is only matched once?
No, "777" does match the pattern you have specified "[5,6,7][5,6,7][5,6,7]"
Following condition in your code will evaluate to true.
if(Integer.toString(shouldFailTest).matches("[5,6,7][5,6,7][5,6,7]"))
It started from I want to compute 1+2+3+...+n, and
It is easy for me to figure out an recursive method to deal with repeat-plus-operation, and the code as follow:
public long toAccumulate(long num)
{
return num == 1 ? 1 : num + toAccumulate(num-1);
}
This method works just fine when use in a range of small number like 1 to 100, however, it fails to work when the parameter up to a big number like 1000000.
I wonder why?
And one leads to another, I write a repeat-times-operation method as follow:
public long toTimes(long num)
{
return num == 1 ? 1 : num * toTimes(num-1);
}
And here comes some interesting result. If I pass 100 as parameter, I will get 0. So I decrease my parameter's value, and I finally got some number when the parameter passing 60, but the result was a very weird negative number -8718968878589280256.
This got me thinking, but it didn't too much time for me to rethink something I have learnt from C, which is long long big data value type. And I assumed that negative number showed off is because the result data too big to fit in the current data type. What amazed me was I realize that there's a BigInteger class in Java, and I remembered this class can operate the big value data, so I changed the first code as follow:
public BigInteger toAccumulate(BigInteger num)
{
return num.equals(1) ? BigInteger.valueOf(1) : (num.add(toAccumulate(num.subtract(BigInteger.valueOf(1)))));
}
But it still didn't work... and this is driving me crazy...
A question I found in the stack overflow which similar to mine
According to the people who answered the question, I guess it may be the same reason that cause the bug in my code.
But since the BigInteger class didn't work, I think this must be the solution to this kind of accumulation problem.
What will you people do when you need to accumulate some number and prevent it go out of the maximum of data type? But is this really the data type problem?
return num.equals(1)
? BigInteger.valueOf(1)
: (num.add(toAccumulate(num.subtract(BigInteger.valueOf(1)))));
should probably be
return num.equals(BigInteger.valueOf(1))
? BigInteger.valueOf(1)
: (num.add(toAccumulate(num.subtract(BigInteger.valueOf(1)))));
...though frankly I'd write it as a method accepting an int and returning a BigInteger.
What if you try this:
public static BigInteger toAccumulate (BigInteger num)
{
if (num.equals(BigInteger.valueOf(1)))
{
return BigInteger.valueOf(1) ;
}
else
{
// 1+2+...+(n-1)+n = (n)(n+1)/2
BigInteger addOne = num.add(BigInteger.valueOf(1));
return num.multiply(addOne).divide(BigInteger.valueOf(2));
}
}
Here's how you can do the 1*2*3*....*(n-1)*n
public static BigInteger toTimes (BigInteger num)
{
// Should check for negative input here
BigInteger product = num;
// while num is greater than 1
while (num.compareTo(BigInteger.valueOf(1)) == 1)
{
BigInteger minusOne = num.subtract(BigInteger.valueOf(1));
product = product.multiply(minusOne);
num = minusOne; // num--;
}
return product;
}
Note: This is essentially the Factorial Function
So i'm writing a little program to practice for my exam coming up, and it involves creating a class file as well as an application file. Basically, i'm not sure if my setup will work because user input is required from the Scanner class, and i'm not aware of a method for Strings similar to, say, the nextInt() or nextDouble() methods. Here is a snippet of what I have written so far, and I was basically wondering how I could make the set methods i'm using work when I need to take user input(some of my set methods use Strings and not primitive data types like an int or double). Just curious if my current format can work once I get around to the application class, or if I need to change my methods to use a numerical input instead of Strings and then use something like a switch or if statement later on to change those numerical values to a String. Here is what i've written so far, from the class file:
import java.text.DecimalFormat;
public class GuitarStore
{
DecimalFormat dollar = new DecimalFormat("$#,##0.00");
private int stockNumber;
private int modelID;
private int pickupType;
private String color;
private String brand;
private String pickupType
private double totalValueOfStock;
public GuitarStore()
{
stockNumber = 0;
modelID = 0;
pickupID = 0;
color = "";
brand = "";
pickupType = "";
totalValueOfStock = 0.0;
}
public GuitarStore(int stkNum, int modID, int pickID, String clor, String brnd,
double totValOfStock)
{
setStock(stkNum);
setModel(modID);
setPickup(pickID);
setColor(clor);
setBrand(brnd);
setTotalValue(totValOfStock);
}
public void setStock(stkNum)
{
if (stkNum > 1 && stkNum <= 500)
{
stockNumber = stkNum;
}
else
{
stockNumber = 0;
}
}
public void setModel(modID)
{
if (modID >= 1 && modID <= 1000)
{
modelID = modID;
}
else
{
modelID = 0;
}
}
public void setPickup(pickID)
{
if (pickID > 1 && pickID <= 3)
{
pickupID = pickID;
}
else
{
pickupID = 0;
}
}
public void setColor(clor)
{
if (clor == "red")
color = clor;
else if (clor == "blue")
color = clor;
else if (clor == "purple")
color = clor;
else if (clor == "green")
color = clor;
else if (clor == "white")
color = clor;
else
System.out.println("We do not carry that color");
Basically, i'm most curious about the setColor method and if/how it will work once I get to the application part of the program. In previous projects, i've just used numbers and not strings which I then converted to a string using a switch statement. This is something totally new to me and i'm going out on a limb trying something new. Since I need to take user input to determine what color they will want, i'm not sure how to parse that since I can't use a method like nextDouble() or nextInt() like I stated above. This is total practice so if anyone can tell me if I have a solid plan or not i'd appreciate it, and also what I should do to take the user input once I get to the application process for the set methods. Thanks, everyone here is always so helpful!!! :)
Scanner does have a next method, which reads a token regardless of type and returns it as a String, as well as a nextLine method, which does what you expect. In general, I would suggest using next or nextLine over nextInt and other type-specific methods, just because you may run into some unexpected behaviour if the input isn't exactly right.
Also, you shouldn't compare two strings with the == operator. In Java, == is a reference (or shallow) comparison, which essentially checks if two objects are stored in the same place on your computer; this works for primitive types (ints, doubles, etc.), because of how they're represented in the language. It will NOT work for Strings, because Strings are complex objects in Java. Instead you should use the equals method, which will do a deep comparison - checking if all of the data is identical.
I'm working on a project for my intro to Java class and we have to format a UML that is
+adjustQuantity(adjustingQuantity:int):void // Adjusts the book stored quantity by the given amount. The final
// must be >= 0
I've got the code for adding the adjusted interval already applied,
public void adjustQuantity(int adjustingQuantity)
{
int iAdjustingQuantity;
int iQuantity= this.quantity;
int iNewQuantity = (this.quantity + iAdjustingQuantity);
if(iNewQuantity <=0)
}
the problem I'm having is getting the value to stop at 0. I would just do an if statement that says "Return 0 if less than 0" but it's not returning anything so I can't do that... So my question is how do I get it to stay positive and not go negative?
Perhaps this?
public void adjustQuantity(int adjustingQuantity) {
int iNewQuantity = this.quantity + adjustingQuantity;
if (iNewQuantity >= 0)
this.quantity = iNewQuantity
else
this.quantity = 0;
}
With the above you guarantee that the quantity gets adjusted only if the new quantity is zero or positive, otherwise we assign zero.
You can assign the variable another time:
public void adjustQuantity(int adjustingQuantity)
{
int iAdjustingQuantity;
int iQuantity= this.quantity;
int iNewQuantity = (this.quantity + iAdjustingQuantity);
if(iNewQuantity <=0)
iNewQuantity = 0;
this.quantity=iNewQuantity;
}
if ((adjustingQuantity+this.quantity) < 0)
throw new Exception("adjustingQuantity must be greater than or equal to zero");
The basic operation should be:
this.iQuantity = Math.max(iQuantity + iAdjustingQuantity, 0);
However, there is no reason to use the i prefix on your integer variables; your methods should be short enough that you don't need the prefix. Besides, suppose your requirements change and and you must switch to longs. Do you just change the type and have:
long iQuantity;
Now, what do you want to happen if the new value is negative? Do you want to set it to zero? Do you want to throw an exception? Do you want to revert? This takes your decision.
#jcalfee314 suggested throwing an Exception; I would suggest a specific subclass of Exception instead. IndexOutOfBoundsException does not seem quite right; I'd use IllegalArgumentException.
Probably the best way to use this in a large program is to use PropertyChangeEvent, PropertyChangeListener and VetoableChangeListener. Look up the JavaBeans specification, Section 7.4. Make iQuantity bound and constrained.