LocalDate: missing methods isEqualOrBefore and isEqualOrAfter - java

Question: How are you handling these use cases?
do you use static helper methods?
do you use the verbose equals followed by isAfter/isBefore?
do you use the negated opposite condition?
do you use 3rd party library helpers?
In daily business, I often need to check if date a <= date b or if date a >= date b.
The internet often suggests to use the negated versions of isBefore/isAfter methods.
In practice I find that I
almost never get these negated comparisons right on the first try (and they should be intuitive and easy).
have a hard time understanding the business logic when reading the code
I guess part of me is still hoping that I just overlooked the corresponding methods in the API (please!).
/**
* #return true if candidate >= reference </br>
* or in other words: <code>candidate.equals(reference) || candidate.isAfter(reference)</code> </br>
* or in other words: <code>!candidate.isBefore(reference) </br>
* or in other words: <code>candidate.compareTo(reference) >= 0
*/
public static boolean isEqualOrAfter(LocalDate candidate, LocalDate reference)
{
return !candidate.isBefore(reference);
}
/**
* #return true if candidate <= reference </br>
* or in other words: <code>candidate.equals(reference) || candidate.isBefore(reference)</code> </br>
* or in other words: <code>!candidate.isAfter(reference) </br>
* or in other words: <code>candidate.compareTo(reference) <= 0
*/
public static boolean isEqualOrBefore(LocalDate candidate, LocalDate reference)
{
return !candidate.isAfter(reference);
}
EDIT: As suggested by Andreas, I added the version with compareTo method, I hope I got them right (without testing).
EDIT 2: Example:
// Manager says: "Show me everything from 3 days ago or later" or "show me everything that's at most 3 days old"
for(Item item : items) {
// negation idiom
if(!item.getDate().isBefore(LocalDate.now().minusDays(3))) {
// show
}
// compareTo idiom
if(item.getDate().compareTo(LocalDate.now().minusDays(3)) >= 0) {
// show
}
// desired
if(item.getDate().isEqualOrAfter(LocalDate.now().minusDays(3))) {
// show
}
}

The methods you seek are unnecesary. That's how you do it:
isEqualOrBefore == !isAfter
isEqualOrAfter == !isBefore

Is compareTo consistent for these types (Well they implement Comparable)?
I remember the inline documentation suggesting the "idiom":
(a.compareTo(b) <operator> 0), so
for isEqualOrBefore: (a.compareTo(b) <= 0)
for isEqualOrAfter: (a.compareTo(b) >= 0)

Related

Merge this if statement with the enclosing one

I'm running my code on sonarqube, but it shows there's an issue with my code, saying"Merge this if statement with the enclosing one." I tried it, but still have no idea how to solve it.
if (splitStrings.length == 2) {
if (!splitStrings[1].matches("\\d{1,3}")
|| Integer.parseInt(splitStrings[1]) > 100
|| Integer.parseInt(splitStrings[1]) < 1) {
throw new IllegalArgumentException("Invalid Input");
}
}
You could do three things:
Either you need to chain the conditions as below:
if (splitStrings.length == 2
&& (!splitStrings[1].matches("\\d{1,3}")
|| Integer.parseInt(splitStrings[1]) > 100
|| Integer.parseInt(splitStrings[1]) < 1)) {
throw new IllegalArgumentException("Invalid Input");
}
You could declare local variable for Integer.parseInt(splitStrings[1]) inside the first if after adding the matches condition in it.
if (splitStrings.length == 2 && splitStrings[1].matches("\\d{1,3}")) {
int val = Integer.parseInt(splitStrings[1]);
if (val > 100 || val < 1)) {
throw new IllegalArgumentException("Invalid Input");
}
}
Even though i won't recommend it, you could also suppress the warning using //NOSONAR in the line in which warning is displayed or add #SuppressWarnings("squid:S1066") at the method level.
Try this.
if (splitStrings.length == 2
&& (!splitStrings[1].matches("\\d{1,3}")
|| Integer.parseInt(splitStrings[1]) > 100
|| Integer.parseInt(splitStrings[1]) < 1)) {
throw new IllegalArgumentException("Invalid Input");
}
You should merge them by && between them and wrap the second with brackets, like:
if(splitStrings.length == 2 && (!splitStrings[1].matches("\\d{1,3}") || Integer.parseInt(splitStrings[1]) > 100 || Integer.parseInt(splitStrings[1]) < 1)){
//code here
}
Integer.parseInt may be skipped altogether if a better regexp is provided to check for the digits in the range [1..100], thus the conditions could be simplified:
if (splitStrings.length == 2 && !splitStrings[1].matches("(?!0)\\d{1,2}|100")) {
throw new IllegalArgumentException("Invalid Input");
}
Online demo of the regexp: (?!0)\d{1,2}|100 validating positive cases 0 < x <= 100
(?!0)\d{1,2} - 1 or 2 digit numbers except 0 excluded with negative lookahead (?!0): 1 - 99
|100 - OR 100
In my opinion the assertion that combining if statements makes code more readable is flawed. Often it makes sense to ask a series of questions in sequence, especially when each part is asking an essentially independent question.
This can (in direct opposition of the SonarQube assertion) make each part more readable. It also allows for correct placement of useful comments in cases where the meaning is not stupidly obvious.
Another valid reason for nested if statements would be to follow certain easily recognized coding patterns. An example would be in ASP.Net applications where Page_Load methods may often have an if (!PostBack) block, which can then contain additional logic that may include additional nested conditions. If there is only one nested condition and it is combined, later changes may need to undo that merge. (There may be a case at that point for refactoring the logic into a separate method at that point, but that is a different subject.)
The question of whether or not to combine nested if statements should be left to the discretion and good judgement of the author (and code reviewer) based on which form is more readable and/or maintainable.
In your particular case, your logic is asking two questions: (1) "Does the input have two parts?" and (2) "Is the second part valid"?
So yes, your nested if statements can be combined into a single (but logically more complex) statement, but this is not necessarily better.

Looking for help on creating more efficient way on doing a lot of checks

Note: Not a duplicate of How do I compare strings in java as I am taking about going through some checks to determine if something is inheriting something something else
Is their a better and more efficient way to do this:
As you can see I am inputting 2 strings then checking them of on a list, as if current = three then it returns true for checking for one, two and three
NOTE: these values(one,two,three) are just placeholders for the example in my use their is no relation between them except that they have a different priority.
public boolean checker(String current, String check) {
if (check.equals("one")) {
if (current.equals("one") || current.equals("two")
|| current.equals("three")) {
return true;
}
}
if (check.equals("two")) {
if (current.equals("two") || current.equals("three")) {
return true;
}
}
if (check.equals("three")) {
if (current.equals("three")) {
return true;
}
}
return false;
}
Here are a few pointers
As Frisch mentioned in comments, use .equals rather than == for String comparison.
Use switch/case
switch (check) {
case "one":
if (current.equals("one")) return true;
case "two":
if (current.equals("two")) return true;
case "three":
if (current.equals("three")) return true;
}
Apart from that, there doesn't seem to be much to do.
Two things.
Don't check strings using equality. Use the .equals() method. You can call it off the string literal. So something like this. Calling it off the string literal is safe even with nulls, which is generally a good thing.
if ("one".equals(check))
You can take advantage of Java's short circuit operators && and ||
if ("one".equals(check)) {
if ("one".equals(current) || "two".equals(current) || "three".equals(current)) {
return true;
}
}
Can become
if ("one".equals(check) && ("one".equals(current) || "two".equals(current) || "three".equals(current))) {
return true;
}
Which will be evaluated from left to right. Since the "one".equals(check) is on the far most left, and is &&'ed with the rest of the statement, Java will bail out of the condition checking if "one".equals(check) is not true, and will not evaluate the rest of the statement.
Since you're just returning true or false, you can also take this a step further and reduce all of your if statements into a single one using De Morgan's laws (http://en.wikipedia.org/wiki/De_Morgan's_laws). Generally you state your boolean if statement in the way that is most natural to you, and then you start simplifying it by applying transformations that keep the logical if statement the same.
A good example of this is, stolen from the below link.
In the context of the main method's program body, suppose the following data is defined:
int score, min = 0, max = 20;
boolean bad, good;
Further suppose that a value is assigned to score, perhaps from a keyboard entry, and I would like to test, with a Boolean expression whether the score is a valid number or not. A good score is in the closed range [0 .. 20], which includes 0 and 20.
good = (score >= min && score <= max);
I would like to get the score from the keyboard in a do while loop, so that I can validate the entry. The logic in my control structure is to demand another entry for the score while the entry is bad. I have a definition of a good entry, and I will use definitions of operators and De Morgan's Law to help me write an expression that represents a bad entry.
good = (score >= min && score <= max); // original definition of good from the logic of my task
good = !(score < min) && !(score > max); // by definition, >= means ! < , <= means ! >
good = !(score < min || score > max); // by De Morgan's' Law
bad = !good ; // bad is not good
bad = !!(score < min || score > max); // substituting for good
bad = score < min || score > max; // double negation is dropped
http://fcmail.aisd.net/~JABEL/1DeMorgansLaw.htm
I would like to update you some thing.
1. We can apply switch cases only on primitive data types but not on objects. As string is object we can't use strings in case/switch statement.
I would like to suggest you to enums/maps in this case.
Please find the below sample programm how i implemented using maps.
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<String, Integer>();
map.put("one", 1);
map.put("two", 2);
map.put("three", 3);
String current = "one";
String check = "one";
if(map.get(check)<=map.get(current)){
System.out.println("Our condition is success");
}
}
Instead of multiple comparison this is better.
---Santhosh

How would I remake compareTo method?

I have
public int compareTo(Object other)
{
}
I need to be able to compare two different sets of numbers and the numbers in the corresponding places.
For example:
Time t1 = new Time(17, 12);
System.out.println(t1);
Time t2 = new Time(9, 45);
System.out.println(t2);
System.out.println("Greater Than:");
System.out.println(t1.compareTo(t2));
And the output would be
1712
0945
Greater Than:
1
In the time class, the first number is hours while the second number is the minutes. I need help comparing the two numbers.
My time class uses
public Time (int y, int x)
{
minute = x;
hour = y;
if (minute>59 || minute<0)
{
minute = 0;
}
if (hour>=24 || hour<0)
{
hour=0;
}
}
How would i compare two new time objects to each other?
First implement the Comparable interface with the correct generic type, in your case Comparable<Time>.
Then you're able to access the other object's attributes.
Your method will now look like this:
public int compareTo(Time otherTime)
{
//... compare things here... like:
return hour.compareTo(otherTime.getHour());
}
This is a sample, you have to implement compare logic yourself, since I don't know if this is an assignment.
The logic has nothing technical. Tell us verbally how you are doing the comparison in your mind when you faced 17:12 & 09:45. If you can speak out in a systematic way, then there should be no problem writing it as code.
I can understand you maybe a total newbie in programming that you have even no clue in writing a most simple line of code. However in programming world, no one is gonna lead you by grabbing your hand to write. You should try to solve it by yourself.
I won't give you a direct answer. However, this is a little example of similar problem. Assume there is a grading system like this, where A1 < A2 < A3 ... < An < B1 < B2 < B3... < C1....
What I am going to do the comparison is, first I will compare the alphabet part, if grade1's alphabet is larger/smaller than grade2's alphabet, I won't need to care about the number part, and I can return -1/1 according to the alphabet being smaller/larger. If the alphabet is the same, then I need to compare the number part, and return 1,-1 and 0 depending on the result.
Then the code will look like something like (half-psuedo code)
public class Grade implements Comparable {
char level; // A,B,C,D
int sublevel; // 1,2,3,4
// ctor, getters/setters etc
#Override
public int compareTo(Grade other) {
// compare the alphabet part
if (this.level < other.level) {
return -1;
} else if (this.level > other.level) {
return 1;
}
// alphabet not larger or smaller, that means equals
// compare the number part
if (this.sublevel< other.sublevel) {
return -1;
} else if (this.sublevel> other.sublevel) {
return 1;
} else { // alphabet and number part are all equals
return 0;
}
}
}
if you can understand what's going on here, then there should be no problem implementing your problem. (Of course there is shorter and cleaner way to implement this. However I think what you need is to learn the basics first)
So your class is Time and i assume it has 2 variables one for minutes and one for seconds. What you need to compare is the t1.minutes to t2.minutes and the t1.seconds to t2.seconds. Your code however is missing a lot of parts and it can't really help us answer your question correctly.
You can use the comparator interface on your Time class.
Doc: http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html
There should be plenty of examples online.

How to JUnit test for any output in Java

I'd like to test the two methods below, but because its based on random output my go-to assertEquals() won't work.
I just want to test to ensure the methods are producing some kind of output. Any ideas?
Novice programmer, appreciate the help.
public void compRandomChoice() {
double choice = (Math.random() * 100 / 100);
if (choice > 0 && choice <= 0.34) {
computer.setChoice(HandThrow.ROCK);
} else if (choice > 0.34 && choice <= 0.67) {
computer.setChoice(HandThrow.PAPER);
} else {
computer.setChoice(HandThrow.SCISSORS);
}
}
public String gameWinner() {
String gameResult;
if (human.getChoice() == computer.getChoice()) {
gameResult = "ITS A TIE!";
} else if (human.getChoice() == HandThrow.ROCK
&& computer.getChoice() == HandThrow.SCISSORS
|| human.getChoice() == HandThrow.PAPER
&& computer.getChoice() == HandThrow.ROCK
|| human.getChoice() == HandThrow.SCISSORS
&& computer.getChoice() == HandThrow.PAPER) {
gameResult = "CONGRATS, YOU WIN!";
} else {
gameResult = "COMPUTER WINS!";
}
return gameResult;
}
I suggest changing compRandomChoice() function as follows
public void compRandomChoice(double rand_no) {
double choice = (rand_no * 100 / 100);
if (choice > 0 && choice <= 0.34) {
computer.setChoice(HandThrow.ROCK);
} else if (choice > 0.34 && choice <= 0.67) {
computer.setChoice(HandThrow.PAPER);
} else {
computer.setChoice(HandThrow.SCISSORS);
}
}
Then in your program, you can call it as compRandomChoice(Math.random()) Now in your Unit Tests,
you can hard-code the input, e.g. compRandomChoice(0.5) and assert that the result is as expected.
Similarly, change public String gameWinner() as public String gameWinner(String human_choice, String computer_choice)
public String gameWinner(String human_choice, String computer_choice) {
String gameResult;
if (human_choice == computer_choice) {
gameResult = "ITS A TIE!";
.......
In your code, you can call the function as gameWinner(human.getChoice(), computer.getChoice()). In your Unit Tests, you can hard code the input (using an approach similar to used for previous function) and assert that you get expected result based on the parameter you are passing.
What you are discovering is that you want to test (assert) that your code behaves correctly given certain inputs, but that you can not easily control the inputs in question as your code is written. Congratulations! You have discovered (one of) the virtues of test-driven development.
The solution is to re-structure your code in a way that makes it easier to test the properties you care about.
What property do you care about for the compRandomChoice function? Perhaps that it produces an output that is evenly distributed across the three choices. To do that, you might imagine writing a short test that iterates over many calls to compRandomChoice and does some simple analysis (and the Law of Large Numbers) to show that you get each choice about a third of the time.
How about for the gameWinner function? There you want to try different combinations of inputs and verify that the correct winner is determined. The inputs to the algorithm are the choices made by the computer and the human. So to test it, you must be able to manufacture human and computer choices and provide them to the algorithm. This would typically be done by using dependency injection...that is providing the objects that your algorithm depends on in the constructor or as a parameter instead of hard-coding them.
For example, the simplest thing to do would be to pass the choices into the gameWinner function and have it return a the winner (e.g., as an enum):
enum Result { PLAYER1, PLAYER2, TIE }
/**
* Determine the game winner.
* #param player1_choice
* #param player2_choice
* #return PLAYER1 .
*/
public Result gameWinner(HandThrow player1_choice, HandThrow player2_choice) {
if (player1_choice.equals(player2_choice)) { return TIE }
...
}
Then the tests are easy to write:
#Test
public void paperBeatsRock() {
assertEquals(gameWinner(HandThrow.ROCK, HandThrow.PAPER), PLAYER2);
}
Take a look at Writing Testable Code; it gives a lot of hints on how to do what you want to do successfully.
I would extract getting random into a package private method
double getRandomChoice() {
return (Math.random() * 100 / 100);
}
so that in the test I could override it
MyClass mc = new MyClass() {
#Override
double getRandomChoice() {
return 2.0;
}
};
For my needs and time available I found the assertNotNull() test method, and used that.
#Test
public void testGameWinner() {
assertNotNull(testLogic.gameWinner());

BigDecimal to SQL NUMBER: check for value larger than precision

In my app, I handle numbers as BigDecimal and store them as NUMBER(15,5). Now I'd need to properly check on Java if the BigDecimal values would fit the column, so that I can generate proper error messages without executing the SQL, catching exceptions and verifying the vendor error code. My database is Oracle 10.3, and such errors cause error 1438.
After some googling, I found no such code for that, so I came up with my own. But I'm really unsatisfied with this code... simple, but at the same time simple enough to doubt its correctness. I tested it with many values, random ones and boundaries, and it seems to work. But as I'm really bad with numbers, I'd like some more robust and well-tested code.
//no constants for easier reading
public boolean testBigDecimal(BigDecimal value) {
if (value.scale() > 5)
return false;
else if (value.precision() - value.scale() > 15 - 5)
return false;
else
return true;
}
Edit: Recent tests did not got an exception for numbers out of scale, just got silently rounded, and I'm not sure what is different between not and when I made these first tests. Such rounding is unacceptable because the application is financial, and any rounding/truncation must be explicit (through BigDecimal methods). Exception-is-gone aside, this test method must assure that the number is not too large for the desired precision, even if by non-significant digits. Sorry about the late clarification.
Thanks for your time.
I'm still curious about this question. My code is still running, and I haven't got some "proof" of correctness or fail situation, or some standard code for this kind of test.
So, I'm putting a bounty on it, hopefully getting any of these.
The following regexp would do the trick too:
public class Big {
private static final Pattern p = Pattern.compile("[0-9]{0,10}(\\.[0-9]{0,5}){0,1}");
public static void main(String[] args) {
BigDecimal b = new BigDecimal("123123.12321");
Matcher m = p.matcher(b.toString());
System.out.println(b.toString() + " is valid = " + m.matches());
}
}
This could be another way to test your code or it could be the code. The regexp requires between 0 and 10 digits optionally followed by a decimal point and 0 to 5 more digits. I didn't know if a sign was needed or not, as I think about it. Tacking something like [+-]{0,1} to the front will do.
Here is a better class, maybe, and a test class with a partial set of tests.
public class Big {
private static final Pattern p = Pattern.compile("[0-9]{0,10}(\\.[0-9]{0,5}){0,1}");
public static boolean isValid(String s) {
BigDecimal b = new BigDecimal(s);
Matcher m = p.matcher(b.toPlainString());
return m.matches();
}
}
package thop;
import junit.framework.TestCase;
/**
* Created by IntelliJ IDEA.
* User: tonyennis
* Date: Sep 22, 2010
* Time: 6:01:15 PM
* To change this template use File | Settings | File Templates.
*/
public class BigTest extends TestCase {
public void testZero1() {
assertTrue(Big.isValid("0"));
}
public void testZero2() {
assertTrue(Big.isValid("0."));
}
public void testZero3() {
assertTrue(Big.isValid("0.0"));
}
public void testZero4() {
assertTrue(Big.isValid(".0"));
}
public void testTooMuchLeftSide() {
assertFalse(Big.isValid("12345678901.0"));
}
public void testMaxLeftSide() {
assertTrue(Big.isValid("1234567890.0"));
}
public void testMaxLeftSide2() {
assertTrue(Big.isValid("000001234567890.0"));
}
public void testTooMuchScale() {
assertFalse(Big.isValid("0.123456"));
}
public void testScientificNotation1() {
assertTrue(Big.isValid("123.45e-1"));
}
public void testScientificNotation2() {
assertTrue(Big.isValid("12e4"));
}
}
one of the problems with your function is that in some cases it may be too restrictive, consider:
BigDecimal a = new BigDecimal("0.000005"); /* scale 6 */
a = a.multiply(new BigDecimal("2")); /* 0.000010 */
return testBigDecimal(a); /* returns false */
As you can see, the scale is not adjusted down. I can't test right now if something similar happens with high-end precision (1e11/2).
I would suggest a more direct route:
public boolean testBigDecimal(BigDecimal value) {
BigDecimal sqlScale = new BigDecimal(100000);
BigDecimal sqlPrecision = new BigDecimal("10000000000");
/* check that value * 1e5 is an integer */
if (value.multiply(sqlScale)
.compareTo(value.multiply(sqlScale)
.setScale(0,BigDecimal.ROUND_UP)) != 0)
return false;
/* check that |value| < 1e10 */
else if (value.abs().compareTo(sqlPrecision) >= 0)
return false;
else
return true;
}
Update
You've asked in a comment if the database would throw an error if we try to insert 0.000010. In fact the database will never throw an error if you try to insert a value with too much precision, it will silently round the inserted value.
The first check is therefore not needed to avoid an Oracle error, I was assuming that you were performing this test to make sure that the value you want to insert is equal to the value you actually inserted. Since 0.000010 and 0.00001 are equal (with BigDecimal.compareTo) shouldn't they both return the same result?
Instead if looping over thousands of random numbers, you could write test cases that stress the 'edges' - the maximum value +.00001, the maximum value, the maximum value - .00001, 0, null, the minimum value -.00001, the minimum value, the minimum value + .00001, and values with 4, 5, and 6 values to the right of the decimal point. There are probably many more.
If you have those in junit, you're good.
Well, since nobody came up with another solution, I'm leaving the code as it is.
I couldn't make this precision/scale test fail, and it always matched the regex solution, so maybe both are correct (I tested the boundaries and with over 5M randomly generated values). I'll use the precision/scale solution, as it is over 85% faster, and may it fail I replace it.
Thanks for your replies Tony.
My previous "answer", still here for history purposes, but I'm looking for a real answer =)

Categories