Reuse part of the same lambda expression - java

I have the following case:
//Case 1
final Set<String> first = A.stream().filter().map().collect()
//Case 2
final Set<String> second = B.stream().filter().map().collect()
As you can see I call the same lambda expression twice but with different "consumer" (A or B). Is there a solution to avoid this duplication ?

Define a method, taking a Collection of the appropriate type (or a Stream, if you don't mind calling parameter.stream() when calling the method):
Set<String> reuse(Collection<SomeType> collection) {
return collection.stream().filter().map().collect();
}
Then invoke like:
final Set<String> first = reuse(A);
final Set<String> second = reuse(B);

First of all: there are no lambdas in your example code.
You are only showing two chained method calls creating a Set as final result.
In that sense, the only thing that makes sense given the example code: putting the common parts
return someCollection.stream().filter().map().collect()
into a small helper method. Maybe a bit more complex than outlined by Andy - as I expect that the lambdas you are talking about are actually used as paramters for the calls to filter() and map(). In that case you could make those parameters of the helper method.
But as much as I am about avoiding code duplication - you should only create such a helper method when the underlying "semantics" are really identical for the two use cases.

You can use Predicate as a type e.g.
Predicate<String> someFilter = e -> e == e; // or something more smart
and use it like
A.stream().filter(someFilter);

Related

Java/Kotlin: Return object from function vs not returning it

Knowing that in Kotlin/Java functions objects are passed as a copy of its reference. I was wondering if Option 2 is better than Option 1. I think in some cases Option 1 is more readable, but I am not sure if it has any drawback.
Option 1
fun modifyListFunction(someList: List): List {
// modifify items in someList
return someList
}
someList = modifyListFunction(someList)
someList = modifyListFunction2(someList)
someList = modifyListFunction3(someList)
Option 2
fun modifyListFunction(someList: List) {
// modifify items in someList
}
modifyListFunction(someList)
modifyListFunction2(someList)
modifyListFunction3(someList)
When a function return an object, then the reading programmer will understand that this function is needed to get some object. If you do something with the object inside the function that returns void, then if you do not read the function, it will not be possible to understand whether this function will affect the object that is passed to it. In addition, the second approach increases the likelihood of errors.
In general, you must adhere to the rule: "If you want to change the input data and do something further with them, the function should return the result. If the input data is used only to read any information from them, then you can not return void"
I would suggest using Kotlin's Extension Functions. The result would be like Option 1 but it would be more readable and easier to chain call.
fun main() {
val list = listOf(Type())
list.func().func2().func3()
}
class Type
fun List<Type>.func(): List<Type> {
// modify list
return this // returns list
}
fun List<Type>.func2() = this
fun List<Type>.func3() = this
In general, programmers reading the signature of option 1 will expect a new list to be returned. So, if you're mutating the list, don't return anything (option 2). If you create a new list, return the new list.
You should use option 1 only if your semantics really makes it obvious that you're returning the same object (e.g. you're building an API that is clearly meant for chaining, like a builder).
But if that were the case, I would probably go for an extension function and make someList a receiver instead of an argument.
Note that it's uncommon for collection types to be used this way, though, so you should probably not go for option 1 in your case.

Use string replace inside java 8 foreach

I have already look at this questions, but my problem is a little different.
I have a "baseString", n HashMap and an output string.
I want to fill the baseString with the hashmap, to construct a json call parameters.
I have already done it with Java 7, in this way:
HashMap<String,Integer> element= getAllElement();
String baseElem="{\"index\":{}}\r\n" +
"{\"name\":\"$name$\",\"age\":$age$}";
String result=baseElem;
for (Map.Entry<String, Integer> entry : element.entrySet()) {
result=result.replace("$name$", entry.getKey());
result=result.replace("$age$", entry.getValue().toString());
result=result+baseElem;
}
result= result.replace(baseElem, "");
Now I want to the same with Java 8,
I have tried in this way:
element.forEach((k,v)->{
result=result.replaceAll("$name$", k);
result=result.replaceAll("$age$", v.toString());
result=result+baseElem;
});
But for each result I have an error
"Local variable result defined in an enclosing scope must be final or
effectively final"
So the question is: I can do that in some kind of way with Java 8 and streams? Or there is no way, and so I can use the simple Java 7 for?
Your approach is going entirely into the wrong direction. This is not only contradicting the functional programming style, the Stream API adopts. Even the loop is horribly inefficient, performing repeated string concatenation and replace operations on the growing result string.
You did a Shlemiel the painter’s algorithm
You actually only want to perform a replace operation on the baseElem template for each map entry and join all results. This can be expressed directly:
Map<String,Integer> element = getAllElement();
String baseElem = "{\"index\":{}}\r\n{\"name\":\"$name$\",\"age\":$age$}";
String result = element.entrySet().stream()
.map(e -> baseElem.replace("$name$", e.getKey())
.replace("$age$", e.getValue().toString()))
.collect(Collectors.joining());
As for "Local variable result defined in an enclosing scope must be final or effectively final" see this answer for further explanation.
As for:
So the question is: I can do that in some kind of way with Java 8 and
streams? Or there is no way, and so I can use the simple Java 7 for?
The logic you're performing with the iterative approach is known as "fold" or "reduce" in the functional world i.e. streams.
So, what you want to do is:
String result = element.entrySet()
.stream()
.reduce(baseElem,
(e, a) -> e.replace("$name$", a.getKey()).replace("$age$",
a.getValue().toString()),
(x, y) -> {
throw new RuntimeException();
});
the third input argument to reduce is known as the combiner function which should be an associative, non-interfering, stateless function for combining two values, which must be compatible with the accumulator function.
if you don't plan on using a parallel stream then the current logic should suffice otherwise you'll need to replace (x, y) -> {...} with the actual logic.
It think, you could use this one:
private static Map<String, Integer> getAllElement() {
Map<String, Integer> map = new HashMap<>();
map.put("\\$name\\$", 666);
map.put("\\$age\\$", 777);
return map;
}
Map<String, Integer> map = getAllElement();
String[] json = { "{\"index\":{}}\r\n{\"name\":\"$name$\",\"age\":$age$}" };
map.forEach((key, val) -> json[0] = json[0].replaceAll(key, String.valueOf(val)));
System.out.println(json[0]);
Output:
{"index":{}}
{"name":"666","age":777}
From the docs,
Any local variable, formal parameter, or exception parameter used but
not declared in a lambda expression must either be declared final or
be effectively final (§4.12.4), or a compile-time error occurs where
the use is attempted.
Similar rules on variable use apply in the body of an inner class (§8.1.3). The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems. Compared to the final restriction, it reduces the clerical burden on programmers.
What is to be a constant here is the reference, but not the values.
You are getting this exception because, you are changing the reference of result. You are re-assigning result to some point to some other String inside your lambda. Thus, conflicting with the JLS, dynamically-changing local variables
Also, Adding to this, You can use Jackson ObjectMapper for producing JSON from Java object(s) instead of hardcoding and replacing stuff.
Define the result variable outside your method something like below
Class A{
String result=null;
Method a(){
//method implementation
}
}

java 8 change list to map using instance of list

I'm try to convert a list to a map using the Collectors.toMap call. The list consists of ActivityReconcile objects. I want to pass an instance for every entry in the list into the toMap call.
The code is below and where I need the instances is denoted by ??.
final List<ActivityReconcile> activePostedList = loader.loadActivePosted(accessToken);
Map<AccountTransactionKey, ActivityReconcile> postedActiveMap =
activePostedList.stream().collect(
Collectors.toMap(
AccountTransactionKey.createNewAccountTransactionKeyFromActivityReconcileRecord(??),??));
If I understood you correctly, you will need something like
Map<AccountTransactionKey, ActivityReconcile> result = choices
.stream()
.collect(Collectors.toMap(
AccountTransactionKey::generate,
Function.identity()));
And the method (in AccountTransactionKey class) will look like
public static AccountTransactionKey generate(ActivityReconcile reconcile) {...}
I've replaced createNewAccountTransactionKeyFromActivityReconcileRec by generate for making the answer more readable and understandable.
To "fix" your code with the least changes, add a lambda parameter:
activePostedList.stream().collect(Collectors.toMap(
ar -> AccountTransactionKey.createNewAccountTransactionKeyFromActivityReconcileRecord(ar)),
o -> o));
or use a method reference:
activePostedList.stream().collect(Collectors.toMap(
AccountTransactionKey::createNewAccountTransactionKeyFromActivityReconcileRecord, o -> o));
btw, I can't recall ever seeing a method name as long as createNewAccountTransactionKeyFromActivityReconcileRecord - for readability, consider reducing it to just create(), since the return type and parameter type are enough to distinguish it from other factory methods you may have.

Using Java 8 Optional for List of String as output

I want to use Optional for a method which returns a List
Lets say the function is
public Output getListOfSomething() {
// In some cases there is nothing to return and hence it makes sense to have return
// type as Optional here
}
Hence the function looks like :
public Optional<List<String>> getListOfSomething() {
// return something only when there is some valid list
}
Now I want to do something if the list is present so something like :
Optional<List<String>> listOfSomething = getListOfSomething();
int size = 0;
listOfSomething.ifPresent(size = listOfSomething.get().size());
I am new to Optional and have gone through the articles about Optional and it seems like this should work however am getting syntax error in my IDE :
method ifPresent is not applicable for the arguments (void).
I wanted to get some help from developers who might be more fluent with lamdas in java 8.
It's important to think about the Semantics here.
Your method could return a List, or "no list".
If it returns a List, it could return an Empty list.
You should ask, "is there a semantic reason to distinguish between an Empty List, and No List?" Sometimes there is a good design reason to make the difference, but it is rare. Think long and hard before deciding that Empty and Null are different in your case. Part of the reason to avoid No List, is that it reduces "special cases" that the client code has to consider. For example, if they have to do something for every item returned, but you could also return null, they have to do a special check for null before going into a for each loop. A for each does nothing if the list is empty.
If a "No List" is distinct from an "Empty List" in your problem domain, then it is sometimes useful to return wrapper class that helps client code distinguish between those conditions, and handle them appropriately. Optional is one such generic class, but your domain may call for something more specific (even if it mimics the functionality of Optional, it might have better semantic definition).
The true functional-programming way is the following:
size = listOfSomething.map(List::size).orElse(0);
But it would be much better to return an empty List instead of Optional.
ifPresent requires a Consumer interface to work. You could do the following:
Optional<List<String>> listOfSomething = getListOfSomething();
Integer[] size = {0};
listOfSomething.ifPresent(list -> size[0]=list.size())
But as stated by Tagir Valeev it would be better to do:
size = listOfSomething.map(List::size).orElse(0);
And it would also be better to return an empty List or even a Stream maybe.

Always avoid in-out parameters in Java?

There's no doubt that in-out parameters leads to confused code since they may increase unexpected/unpredictabled side-effects.
So, many good programmers say :
Avoid in-out parameters for changing mutable method parameters. Prefer to keep parameters unchanged.
For a perfectionist programmer who expects his code to be the most clean and understandable, does this "rule" must be applied in all case ?
For instance, suppose a basic method for adding elements to a simple list, there's two ways :
First way (with in-out parameter):
private void addElementsToExistingList(List<String> myList){
myList.add("Foo");
myList.add("Bar");
}
and the caller being :
List<String> myList = new ArrayList<String>();
//.......Several Instructions (or not) .....
addElementsToExistingList(myList);
Second way without out parameter :
private List<String> addElementsToExistingList(List<String> originalList){
List<String> filledList = new ArrayList<String>(originalList); //add existing elements
filledList.add("Foo");
filledList.add("Bar");
return filledList;
}
and the caller being :
List<String> myList = new ArrayList<String>();
//.......Several Instructions (or not) .....
myList.addAll(addElementsToExistingList(myList));
Pros of second way :
Parameter are not modified => no risk of unexpected side-effects for a new code reader.
Cons of second way :
Very verbose and very less readable ...
Of course, you would tell me that for a code as simple as this one, first way is really more convenient.
But, if we don't consider the difficulty of any concept/code, I juge the second way more logical and obvious for any readers (beginners or not).
However, it violates the CQS principle that consider "command" methods having void return with potential (but allowed since it's the convention) side-effects and "query" methods having a return type and without side-effects.
So, what should a motivate programmer adopt ? Mix of two accorging to the code case ? Or keep the "law" expecting to always avoid in-out parameters...
(Of course, method for adding Element is named for expliciting the example, and would be a bad name choice in real code).
I think the law should be:
Use what is more straight-forward, but always, always document the behavior of your methods extensively.
Your second example is a very nice case where without documentation you would have a guaranteed bug: the name of the method is addElementsToExistingList, but the method does not add elements to the existing list - it creates a new one. A counter-intuitive and misleading name, to say the least...
There is a third way. Wrap List<String> into a class that knows how to add elements to itself:
class ElementList {
private List<String> = new ArrayList<String>();
public void addElements(Element... elements);
}
I like this approach because it keeps the List implementation private. You don't have to worry if someone passes an immutable list to your method or whether parameters are modified. The code is simpler. Long method names like addElementsToExistingList are code smells that an object is trying to do something another object should be doing.
You should always document when mutating an object that is a parameter because otherwise this can have unintended side effects for the caller. In the first case I agree with the others that have commented that the method name is sufficient documentation.
In your second example, the elements that are already present in myList seem to be added twice. In fact you could entirely remove the parameter of the addElementsToExistingList method and rewrite it as:
private List<String> getElements() {
List<String> filledList = new ArrayList<String>();
filledList.add("Foo");
filledList.add("Bar");
return filledList;
}
List<String> myList = new ArrayList<String>();
//.......Several Instructions (or not) .....
myList.addAll(getElements());
Note that this code is not equivalent to your second example because the elements are only added once, but I think this is actually what you intended. This is the style that I usually prefer. This code is easier to understand and more flexible than the first example without adding extra code (it may degrade performance very slightly but this usually isn't a concern). The client of getElements() can now also do other things with the element list besides adding it to an existing collection.
It's fine to change/mutate parameters as long as it's documented. And of course with a method name of "addElementsToExistingList", what else should someone expect? However, as someone previously pointed out, your second implementation returns a copy and doesn't modify the original, so the method name is now misleading. Your first way is a perfectly acceptable way of doing things. The only other additional improvements is to possibly add a true/false value to the return indicating true if only all the elements were added to the list.
In the case of your example the name makes it clear - "addElementsToExistingList" to me seems pretty clearly to hint that you're going to .. er.. you know. But your concern would be justified with a less obvious name.
For example, in ruby this is commonly handled with naming conventions
"a".upcase => gives you the uppercase of the variable, leaves the original unchanged
"a".upcase! => alters the original variable

Categories