I'm very new to Java. I'm faced with two classes, FooRequest and BarRequest. (Simplified for this question, of course.)
public class FooRequest {
private String a;
private String b;
private String c;
private DateTime x;
private DateTime y;
private BigDecimal z;
// ... and more members
// ... getters and setters for each member
}
And the other class:
public class BarRequest {
private Optional<DateTime> x;
private Optional<DateTime> y;
private Optional<BigDecimal> z;
// ... getters and setters for each member
}
These were written by different people, one preferring null checks upon use, the other preferring Optional. But because FooRequest has many more members, is in widespread use, and completely covers all of BarRequest's members, I'm tasked with getting rid of BarRequest, using the more popular FooRequest instead.
Now, at first I thought I might just "upgrade" FooRequest's members (at least the 3 used by BarRequest) to Optional<>. However, this caused numerous compilation issues (basically, everywhere FooRequest was returned or used). I learned Optional<T> cannot drop-in replace T.
My team-lead confirmed it was not practical to keep Optional<>. To minimize changes, we'd want to rewrite any code previously using Optional<>. For example,
request.getDateBegin().ifPresent((dateBegin) -> {
if (!dateBegin.equals(ad.startDate())) {
// ...
}
}
Here's my attempt at converting this:
if (request.getDateBegin() != null) {
DateTime dateBegin = request.getDateBegin();
if (!dateBegin.equals(ad.startDate())) {
// ...
}
}
Is this correct? Am I missing something by simply doing a null comparison? Is there any way to use a lambda expression inside and avoid creating a DateTime temporary?
Yes, it seems to be that your attempt to convert the optional code into the typical imperative code is correct in terms of functionality. However, calling request.getDateBegin() twice is sub-optimal even if the call is not expensive it can be avoided.
Thus, I'd cache the result of request.getDateBegin() into a variable and operate on that.
If you're going to do this type of logic many times then you can put it into a method as such:
public boolean someMethodName(DateTime date, DateTime another){
if(date != null && !date.equals(another)){
// do logic
return true; // successful
}
return false; // not successful
}
the return type of the method is arguable so I'll leave that to you to decide.
if (request.getDateBegin() != null) {
DateTime dateBegin = request.getDateBegin();
if (!dateBegin.equals(ad.startDate())) {
// ...
}
}
can be replaced with
Optional.ofNullable(request.getDateBegin())
.filter(date -> !date.equals(ad.startDate()))
.ifPresent(date -> {
// ... whatever
});
Related
I'm having an argument with my friend and I would like to know your opinion.
In a test do you think that is better to compare field by field or just create a expectedResultObject and compare it.
For instance:
Assert.That(obj.Foo).isEqualTo(FOO);
Assert.That(obj.Test).isEqualTo(TEST);
vs
Foo expected = new Foo(FOO, TEST);
assertThat(obj).usingRecursiveComparison().isEqualTo(expected);
In this example we only have two fields but we can have allot more.
Thanks
If you can have multiple fields, the expected method is better because you'll be adding the other fields inside the constructors' params. Imagine if you have 100 fields, adding them line by line as you suggested in your first example would be a headache, while adding in the params would be a bit simpler.
Between the two possibilities, I prefer the one without the usingRecursiveComparison().
I wanted to add a few thins :
An object is not a data toolbox, so it's not a good thing to add getter/setter to test your object's creation. It's better test a behaviour, a method where you can test the return.
Generally I'm not fond of writing more than one assertion in a test.
There is a technique which made assertions more lisibles (with AssertJ but I think you can make this kind of thing with Hamcrest).
The initial class :
public class Amount {
private int value;
public Integer add(int amountToAdd) {
value += amountToAdd;
return value;
}
}
Create an Asserter :
public class IntegerAsserter extends org.assertj.core.api.AbstractAssert<IntegerAsserter, Integer> {
IntegerAsserter(Integer actual) {
super(IntegerAsserter.class, actual);
}
public IntegerAsserter isBetweenOneOrTwo() {
Assert.assertTrue(actual < 2);
Assert.assertTrue(actual > 1);
return this;
}
}
Create a new Assertions :
public class Assertions extends org.fest.assertions.Assertions {
public static IntegerAsserter assertThat(Integer actual) {
return new IntegerAsserter(actual);
}
}
And then use it :
public void should_be_between_one_or_two {
Amount amount = new Amount(0);
Integer newAmount = amount.add(1);
Assertions.assertThat(obj).isBetweenOneOrTwo();
}
Modifying a local variable in forEach gives a compile error:
Normal
int ordinal = 0;
for (Example s : list) {
s.setOrdinal(ordinal);
ordinal++;
}
With Lambda
int ordinal = 0;
list.forEach(s -> {
s.setOrdinal(ordinal);
ordinal++;
});
Any idea how to resolve this?
Use a wrapper
Any kind of wrapper is good.
With Java 10+, use this construct as it's very easy to setup:
var wrapper = new Object(){ int ordinal = 0; };
list.forEach(s -> {
s.setOrdinal(wrapper.ordinal++);
});
With Java 8+, use either an AtomicInteger:
AtomicInteger ordinal = new AtomicInteger(0);
list.forEach(s -> {
s.setOrdinal(ordinal.getAndIncrement());
});
... or an array:
int[] ordinal = { 0 };
list.forEach(s -> {
s.setOrdinal(ordinal[0]++);
});
Note: be very careful if you use a parallel stream. You might not end up with the expected result. Other solutions like Stuart's might be more adapted for those cases.
For types other than int
Of course, this is still valid for types other than int.
For instance, with Java 10+:
var wrapper = new Object(){ String value = ""; };
list.forEach(s->{
wrapper.value += "blah";
});
Or if you're stuck with Java 8 or 9, use the same kind of construct as we did above, but with an AtomicReference...
AtomicReference<String> value = new AtomicReference<>("");
list.forEach(s -> {
value.set(value.get() + s);
});
... or an array:
String[] value = { "" };
list.forEach(s-> {
value[0] += s;
});
This is fairly close to an XY problem. That is, the question being asked is essentially how to mutate a captured local variable from a lambda. But the actual task at hand is how to number the elements of a list.
In my experience, upward of 80% of the time there is a question of how to mutate a captured local from within a lambda, there's a better way to proceed. Usually this involves reduction, but in this case the technique of running a stream over the list indexes applies well:
IntStream.range(0, list.size())
.forEach(i -> list.get(i).setOrdinal(i));
If you only need to pass the value from the outside into the lambda, and not get it out, you can do it with a regular anonymous class instead of a lambda:
list.forEach(new Consumer<Example>() {
int ordinal = 0;
public void accept(Example s) {
s.setOrdinal(ordinal);
ordinal++;
}
});
As the used variables from outside the lamda have to be (implicitly) final, you have to use something like AtomicInteger or write your own data structure.
See
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#accessing-local-variables.
An alternative to AtomicInteger is to use an array (or any other object able to store a value):
final int ordinal[] = new int[] { 0 };
list.forEach ( s -> s.setOrdinal ( ordinal[ 0 ]++ ) );
But see the Stuart's answer: there might be a better way to deal with your case.
Yes, you can modify local variables from inside lambdas (in the way shown by the other answers), but you should not do it. Lambdas have been made for functional style of programming and this means: No side effects. What you want to do is considered bad style. It is also dangerous in case of parallel streams.
You should either find a solution without side effects or use a traditional for loop.
If you are on Java 10, you can use var for that:
var ordinal = new Object() { int value; };
list.forEach(s -> {
s.setOrdinal(ordinal.value);
ordinal.value++;
});
You can wrap it up to workaround the compiler but please remember that side effects in lambdas are discouraged.
To quote the javadoc
Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement
A small number of stream operations, such as forEach() and peek(), can operate only via side-effects; these should be used with care
I had a slightly different problem. Instead of incrementing a local variable in the forEach, I needed to assign an object to the local variable.
I solved this by defining a private inner domain class that wraps both the list I want to iterate over (countryList) and the output I hope to get from that list (foundCountry). Then using Java 8 "forEach", I iterate over the list field, and when the object I want is found, I assign that object to the output field. So this assigns a value to a field of the local variable, not changing the local variable itself. I believe that since the local variable itself is not changed, the compiler doesn't complain. I can then use the value that I captured in the output field, outside of the list.
Domain Object:
public class Country {
private int id;
private String countryName;
public Country(int id, String countryName){
this.id = id;
this.countryName = countryName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
Wrapper object:
private class CountryFound{
private final List<Country> countryList;
private Country foundCountry;
public CountryFound(List<Country> countryList, Country foundCountry){
this.countryList = countryList;
this.foundCountry = foundCountry;
}
public List<Country> getCountryList() {
return countryList;
}
public void setCountryList(List<Country> countryList) {
this.countryList = countryList;
}
public Country getFoundCountry() {
return foundCountry;
}
public void setFoundCountry(Country foundCountry) {
this.foundCountry = foundCountry;
}
}
Iterate operation:
int id = 5;
CountryFound countryFound = new CountryFound(countryList, null);
countryFound.getCountryList().forEach(c -> {
if(c.getId() == id){
countryFound.setFoundCountry(c);
}
});
System.out.println("Country found: " + countryFound.getFoundCountry().getCountryName());
You could remove the wrapper class method "setCountryList()" and make the field "countryList" final, but I did not get compilation errors leaving these details as-is.
To have a more general solution, you can write a generic Wrapper class:
public static class Wrapper<T> {
public T obj;
public Wrapper(T obj) { this.obj = obj; }
}
...
Wrapper<Integer> w = new Wrapper<>(0);
this.forEach(s -> {
s.setOrdinal(w.obj);
w.obj++;
});
(this is a variant of the solution given by Almir Campos).
In the specific case this is not a good solution, as Integer is worse than int for your purpose, anyway this solution is more general I think.
Goal:
Represent subset of Strings created from Strings defined in abstract class
test if string on input belongs to given subset
Initial solution:
Let's have list of possible events.
/**
* List of events.
*/
public abstract class EventKeys {
public static final String KEY_EVENT_1 = "EVENT_1";
public static final String KEY_EVENT_2 = "EVENT_2";
public static final String KEY_EVENT_3 = "EVENT_3";
public static final String KEY_EVENT_4 = "EVENT_4";
public static final String KEY_EVENT_5 = "EVENT_5";
public static final String KEY_EVENT_6 = "EVENT_6";
public static final String KEY_EVENT_7 = "EVENT_7";
//etc ..
}
I want make subset of these events for example events 1,3,5 and only for these events allow some action. The goal is make method boolean isEventAllowed(String eventKey) which will say if event belongs to subset of allowed events.
The really naive way to do this is:
/**
* Allow only events 1,3,5
*/
private isEventAllowed(String eventKey) {
if(eventKey.equals(EventKeys1.KEY_EVENT_1)) {
return true;
} else if(eventKey.equals(EventKeys1.KEY_EVENT_3)) {
return true;
} else if(eventKey.equals(EventKeys1.KEY_EVENT_3)) {
return true;
} else {
return false;
}
}
The I feel this approach is not very convinient. I need better way to represent the subset of strings and provide action does input string belongs to defined subset?
Other possible solutions:
As other options i was thinking about other two options, but I'm still not sure if its good way to do it.
1)enum - create enum of strings
Put in enum: EventKeys1.KEY_EVENT_1, EventKeys1.KEY_EVENT_2, EventKeys1.KEY_EVENT_3
Test does String keyEvent belons to defined enum?
2) list
create list List<String> subset and put there
EventKeys1.KEY_EVENT_1, EventKeys1.KEY_EVENT_2, EventKeys1.KEY_EVENT_3
test if String keyEvent belongs to list subset
PLEASE READ THIS BEFORE ANSWER:
class EventKeys is given, can't be changed, main set of options
I need somehow represent subset
I need advice for better implementation of method isAllowedEvent(String keyEvent) which returns true if input string
belongs to defined subset
How about something like this?
private boolean isEventAllowed(String eventKey) {
return Arrays.asList(KEY_EVENT_1, KEY_EVENT_3, KEY_EVENT_5).contains(eventKey);
}
Readability could be improved following John Fergus' comment by using something like this:
private static List<String> SUBSET = Arrays.asList(KEY_EVENT_1, KEY_EVENT_3, KEY_EVENT_5);
private boolean isEventAllowed(String eventKey) {
return SUBSET.contains(eventKey);
}
While a Set holding the allowed values is usually the preferred option, there are also possible syntactical improvements for your original code which you should become aware of, as their general pattern applies to other situations as well.
A statement like
if(condition1)
action;
else if(condition2)
/* (same) */ action;
…
is redundant and may be replaced by
if(condition1 || condition2)
action;
…
similarly
if(condition)
return true;
else
return false;
is redundant and may (or even should) be replaced by
return condition;
Putting both together, your original code becomes
private boolean isEventAllowed(String eventKey) {
return eventKey.equals(EventKeys1.KEY_EVENT_1)
|| eventKey.equals(EventKeys1.KEY_EVENT_3)
|| eventKey.equals(EventKeys1.KEY_EVENT_5);
}
Alternatively, you can use a switch statement:
private boolean isEventAllowed(String eventKey) {
switch(eventKey) {
case EventKeys1.KEY_EVENT_1:
case EventKeys1.KEY_EVENT_3:
case EventKeys1.KEY_EVENT_5:
return true;
default:
return false;
}
}
Not everyone likes this coding style, but that’s more an issue of project or company policies. There are situation, where such a switch statement still is the cleanest solution. One advantage over if statements and even the Set approach is that the compiler will immediately shout if you mistakenly name the same constant twice rather than the intended constant (a typical copy&paste error), like you do in your third if statement where you use KEY_EVENT_3 instead of the intended KEY_EVENT_5…
Most people understand the innate benefits that enum brings into a program verses the use of int or String. See here and here if you don't know. Anyway, I came across a problem that I wanted to solve that kind of is on the same playing field as using int or String to represent a constant instead of using an enum. This deals specifically with String.format(...).
With String.format, there seems to be a large opening for programmatic error that isn't found at compile-time. This can make fixing errors more complex and / or take longer.
This was the issue for me that I set out to fix (or hack a solution). I came close, but I am not close enough. For this problem, this is more certainly over-engineered. I understand that, but I just want to find a good compile-time solution to this, that provides the least amount of boiler-plate code.
I was writing some non-production code just to write code with the following rules.
Abstraction was key.
Readability was very important
Yet the simplest way to the above was preferred.
I am running on...
Java 7 / JDK 1.7
Android Studio 0.8.2
These are unsatisfactory
Is there a typesafe alternative to String.format(...)
How to get string.format to complain at compile time
My Solution
My solution uses the same idea that enums do. You should use enum types any time you need to represent a fixed set of constants...data sets where you know all possible values at compile time(docs.oracle.com). The first argument in String.format seems to fit that bill. You know the whole string beforehand, and you can split it up into several parts (or just one), so it can be represented as a fixed set of "constants".
By the way, my project is a simple calculator that you probably seen online already - 2 input numbers, 1 result, and 4 buttons (+, -, ×, and ÷). I also have a second duplicate calculator that has only 1 input number, but everything else is the same
Enum - Expression.java & DogeExpression.java
public enum Expression implements IExpression {
Number1 ("%s"),
Operator (" %s "),
Number2 ("%s"),
Result (" = %s");
protected String defaultFormat;
protected String updatedString = "";
private Expression(String format) { this.defaultFormat = format; }
// I think implementing this in ever enum is a necessary evil. Could use a switch statement instead. But it would be nice to have a default update method that you could overload if needed. Just wish the variables could be hidden.
public <T> boolean update(T value) {
String replaceValue
= this.equals(Expression.Operator)
? value.toString()
: Number.parse(value.toString()).toString();
this.updatedString = this.defaultFormat.replace("%s", replaceValue);
return true;
}
}
...and...
public enum DogeExpression implements IExpression {
Total ("Wow. Such Calculation. %s");
// Same general code as public enum Expression
}
Current Issue
IExpression.java - This is a HUGE issue. Without this fixed, my solution cannot work!!
public interface IExpression {
public <T> boolean update(T Value);
class Update { // I cannot have static methods in interfaces in Java 7. Workaround
public static String print() {
String replacedString = "";
// for (Expression expression : Expression.values()) { // ISSUE!! Switch to this for Expression
for (DogeExpression expression : DogeExpression.values()) {
replacedString += expression.updatedString;
}
return replacedString;
}
}
}
So Why Is This An Issues
With IExpression.java, this had to hacked to work with Java 7. I feel that Java 8 would have played a lot nicer with me. However, the issue I am having is paramount to getting my current implementation working The issue is that IExpression does not know which enum to iterate through. So I have to comment / uncomment code to get it to work now.
How can I fix the above issue??
How about something like this:
public enum Operator {
addition("+"),
subtraction("-"),
multiplication("x"),
division("÷");
private final String expressed;
private Operator(String expressed) { this.expressed = expressed; }
public String expressedAs() { return this.expressed; }
}
public class ExpressionBuilder {
private Number n1;
private Number n2;
private Operator o1;
private Number r;
public void setN1(Number n1) { this.n1 = n1; }
public void setN2(Number n2) { this.n2 = n2; }
public void setO1(Operator o1) { this.o1 = o1; }
public void setR(Number r) { this.r = r; }
public String build() {
final StringBuilder sb = new StringBuilder();
sb.append(format(n1));
sb.append(o1.expressedAs());
sb.append(format(n2));
sb.append(" = ");
sb.append(format(r));
return sb.toString();
}
private String format(Number n) {
return n.toString(); // Could use java.text.NumberFormat
}
}
I am in the process of refactoring my existing code. It actually works fine, but it is a bit cluttered with multiple if-else conditionals checking the value of one variable and change the value of a second variable to an updated value taken from a fixed enumeration structure.
else if (var1 == 'valueX')
{
if (var2 == MyEnum.A)
var2 = MyEnum.B;
else if (var2 == MyEnum.B)
var2 = MyEnum.C;
else if (var2 == MyEnum.C)
var2 = MyEnum.D;
else if (var2 == MyEnum.D)
var2 = MyEnum.A;
}
else if (....)
{
..similar block of conditionals
}
I am a bit confused as to what is the best way to refactor and clean-up this code. Would you suggest the use of a switch perhaps? Or something more elegant?
Thanks in advance!
The classic answer to refactoring conditionals is Replace Conditional With Polymorphism. In this case, if each of MyEnum knew what its successor was, you could simply say (in the 'valuex' case: var2 = var2.successor. For var1 - if it could be an object that implemented an interface that knew how to handle whatever you're doing inside the loop, and each implementing class knew what it, specifically, should do... Well, you'd be done.
Update:
And here's a dandy little successor function in a test case:
public class EnumTest extends TestCase {
private enum X {
A, B, C;
public X successor() {
return values()[(ordinal() + 1) % values().length];
}
};
public void testSuccessor() throws Exception {
assertEquals(X.B, X.A.successor());
assertEquals(X.C, X.B.successor());
assertEquals(X.A, X.C.successor());
}
}
At least with J2SE 1.5 forward, you can give enums extra attributes. This means you might be able to replace that entire string of if-else with something that looks like
var2 = var1.getNextInSequence();
Now, in this case, it looks like you would want the attribute to be a reference to another enum, which adds some wrinkles, for example you can't forward reference enums when you initialize them, but there might be a workable solution for you this way.
When the attributes aren't other instances of the same enum, this kind of thing will work:
public enum Animal {
FOX(4),
CHICKEN(2),
WORM(0);
private int countLegs;
Animal(int n) {
countLegs = n;
}
public int getLegCount() {
return countLegs;
}
// .. more getters setters etc
}
But when the enum is self-referential, you have to be careful about the order of declaration of your instances. I.e., this will have some issues:
public enum Animal {
FOX(4, CHICKEN), // 'CHICKEN' doesn't exist yet
WORM(0, null),
CHICKEN(2, WORM); // this actually will compile
private int countLegs;
private Animal eatsWhat;
Animal(int n, Animal dinner) {
countLegs = n;
eatsWhat = dinner;
}
public int getLegCount() {
return countLegs;
}
// .. getters, setters, etc
}
So if you had need of a circular set of references among the enums, you'd have to work something else out, but if not, you could use this technique, though you may have to order your enum instances just so to make it work.
You can use a simple map:
enum MyEnum { A, B, C };
Map<MyEnum, MyEnum> VALUE_X = new HashMap<MyEnum, MyEnum>() {{
put(MyEnum.A, MyEnum.B);
put(MyEnum.B, MyEnum.C);
...
}};
// define another kind of ordering
Map<MyEnum, MyEnum> VALUE_Y = new HashMap<MyEnum, MyEnum>() {{
put(MyEnum.A, MyEnum.D);
put(MyEnum.B, MyEnum.A);
...
}};
This way, the logic of the next var2 value isn't hard-coded in the enum itself, and can be dependant of context (i.e. value of var1):
if ("valueX".equals(var1)) { // use equals() instead of == for Strings
var2 = VALUE_X.get(var2);
}
else if ("valueY".equals(var1)) {
var2 = VALUE_Y.get(var2);
}