How to call a function inside stream of hash map object , & accumulate sum based on output of method called inside stream - java-8

double finalPrice = 0;
for(Map.Entry<Integer, Integer> eachBasketItemEntry:itemsInBasket.entrySet()){
Integer itemId = eachBasketItemEntry.getKey();
if(itemPricingRuleMap.containsKey(itemId)){
//calculate pricing based on pricing rule for that item code
finalPrice+=calculateItemPrice(itemId,eachBasketItemEntry.getValue(),itemPricingRuleMap);
}
else{
throw new IllegalArgumentException("No pricing rule regsitered for the item with item id"+itemId);
}
}
return finalPrice;
private double calculateItemPrice(Integer itemId, Integer itemsCount,Map<Integer, PricingRule> itemPricingRuleMap) {
PricingRule pricingRule = itemPricingRuleMap.get(itemId);
return pricingRule.calculatePrice(itemsCount);
}
How to convert this into java8 streams?
double a1 = itemsInBasket.entrySet().stream().forEach(eachBasketItemEntry->{
double finalPrice = 0;
Integer itemId = eachBasketItemEntry.getKey();
finalPrice+= calculateItemPrice(itemId,eachBasketItemEntry.getValue(),itemPricingRuleMap);
})
Tried doing this but Im unsure how to proceed from here..
Can any one help.
Im new to java 8 streams
Thank you.

You can refer the below sample code whenever some one wants to iterate over the collection and wants to get the reduced single value output.
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
Map<String,Integer> employeeSalaryMap = new HashMap<>();
employeeSalaryMap.put("emp1",10000);
employeeSalaryMap.put("emp2",20000);
employeeSalaryMap.put("emp3",30000);
employeeSalaryMap.put("emp4",40000);
employeeSalaryMap.put("emp5",50000);
int totalSalaryOfAllEmployees1 = employeeSalaryMap.values().stream().mapToInt(Integer::intValue).sum();
int totalSalaryOfAllEmployees2 = employeeSalaryMap.entrySet().stream().map(Map.Entry::getValue)
.reduce(Integer::sum).orElseThrow(Exception::new);
System.out.println("totalSalaryOfAllEmployees1:: " + totalSalaryOfAllEmployees1);
System.out.println("totalSalaryOfAllEmployees2:: " + totalSalaryOfAllEmployees2);
}
}
**Output**
totalSalaryOfAllEmployees1:: 150000
totalSalaryOfAllEmployees2:: 150000
Both the operations will give you the same result.
Recommended to use: mapToInt/mapToDouble based on the requirements.
Thanks

You can use .map() to map your result calculated from calculateItemPrice method and then use reduce() operation to get required result.
Wrote a sample example for explanation
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
class Main {
public static void main(String[] args) {
Map<Integer, Integer> itemsInBasket = new HashMap<Integer, Integer>();//Creating HashMap
itemsInBasket.put(1, 5); //Put elements in Map
itemsInBasket.put(2, 6);
itemsInBasket.put(3, 7);
itemsInBasket.put(4, 8);
int a1 = itemsInBasket
.entrySet()
.stream()
.map(e -> (e.getKey() + e.getValue()))
.reduce(Integer::sum).orElseThrow(NoSuchElementException::new);
System.out.println(a1);
}
}
For your case : below code can help
double a1 = itemsInBasket
.entrySet()
.stream()
.map(e->calculateItemPrice(e.getKey(), e.getValue(), itemPricingRuleMap))
.reduce(Double::sum).orElseThrow(NoSuchElementException::new);
EDIT : As #Holger Suggested it can be rewritten as
double a1 = itemsInBasket
.entrySet()
.stream()
.mapToDouble(e->calculateItemPrice(e.getKey(), e.getValue(), itemPricingRuleMap))
.sum().orElseThrow(NoSuchElementException::new);
Let me know in comments further if you face further issues.
Thanks.

Related

java 8 streams grouping and creating Map<String, Set<String>> issue [duplicate]

In Java 8 how can I filter a collection using the Stream API by checking the distinctness of a property of each object?
For example I have a list of Person object and I want to remove people with the same name,
persons.stream().distinct();
Will use the default equality check for a Person object, so I need something like,
persons.stream().distinct(p -> p.getName());
Unfortunately the distinct() method has no such overload. Without modifying the equality check inside the Person class is it possible to do this succinctly?
Consider distinct to be a stateful filter. Here is a function that returns a predicate that maintains state about what it's seen previously, and that returns whether the given element was seen for the first time:
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
Then you can write:
persons.stream().filter(distinctByKey(Person::getName))
Note that if the stream is ordered and is run in parallel, this will preserve an arbitrary element from among the duplicates, instead of the first one, as distinct() does.
(This is essentially the same as my answer to this question: Java Lambda Stream Distinct() on arbitrary key?)
An alternative would be to place the persons in a map using the name as a key:
persons.collect(Collectors.toMap(Person::getName, p -> p, (p, q) -> p)).values();
Note that the Person that is kept, in case of a duplicate name, will be the first encontered.
You can wrap the person objects into another class, that only compares the names of the persons. Afterward, you unwrap the wrapped objects to get a person stream again. The stream operations might look as follows:
persons.stream()
.map(Wrapper::new)
.distinct()
.map(Wrapper::unwrap)
...;
The class Wrapper might look as follows:
class Wrapper {
private final Person person;
public Wrapper(Person person) {
this.person = person;
}
public Person unwrap() {
return person;
}
public boolean equals(Object other) {
if (other instanceof Wrapper) {
return ((Wrapper) other).person.getName().equals(person.getName());
} else {
return false;
}
}
public int hashCode() {
return person.getName().hashCode();
}
}
Another solution, using Set. May not be the ideal solution, but it works
Set<String> set = new HashSet<>(persons.size());
persons.stream().filter(p -> set.add(p.getName())).collect(Collectors.toList());
Or if you can modify the original list, you can use removeIf method
persons.removeIf(p -> !set.add(p.getName()));
There's a simpler approach using a TreeSet with a custom comparator.
persons.stream()
.collect(Collectors.toCollection(
() -> new TreeSet<Person>((p1, p2) -> p1.getName().compareTo(p2.getName()))
));
We can also use RxJava (very powerful reactive extension library)
Observable.from(persons).distinct(Person::getName)
or
Observable.from(persons).distinct(p -> p.getName())
You can use groupingBy collector:
persons.collect(Collectors.groupingBy(p -> p.getName())).values().forEach(t -> System.out.println(t.get(0).getId()));
If you want to have another stream you can use this:
persons.collect(Collectors.groupingBy(p -> p.getName())).values().stream().map(l -> (l.get(0)));
You can use the distinct(HashingStrategy) method in Eclipse Collections.
List<Person> persons = ...;
MutableList<Person> distinct =
ListIterate.distinct(persons, HashingStrategies.fromFunction(Person::getName));
If you can refactor persons to implement an Eclipse Collections interface, you can call the method directly on the list.
MutableList<Person> persons = ...;
MutableList<Person> distinct =
persons.distinct(HashingStrategies.fromFunction(Person::getName));
HashingStrategy is simply a strategy interface that allows you to define custom implementations of equals and hashcode.
public interface HashingStrategy<E>
{
int computeHashCode(E object);
boolean equals(E object1, E object2);
}
Note: I am a committer for Eclipse Collections.
Similar approach which Saeed Zarinfam used but more Java 8 style:)
persons.collect(Collectors.groupingBy(p -> p.getName())).values().stream()
.map(plans -> plans.stream().findFirst().get())
.collect(toList());
You can use StreamEx library:
StreamEx.of(persons)
.distinct(Person::getName)
.toList()
I recommend using Vavr, if you can. With this library you can do the following:
io.vavr.collection.List.ofAll(persons)
.distinctBy(Person::getName)
.toJavaSet() // or any another Java 8 Collection
Extending Stuart Marks's answer, this can be done in a shorter way and without a concurrent map (if you don't need parallel streams):
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
final Set<Object> seen = new HashSet<>();
return t -> seen.add(keyExtractor.apply(t));
}
Then call:
persons.stream().filter(distinctByKey(p -> p.getName());
My approach to this is to group all the objects with same property together, then cut short the groups to size of 1 and then finally collect them as a List.
List<YourPersonClass> listWithDistinctPersons = persons.stream()
//operators to remove duplicates based on person name
.collect(Collectors.groupingBy(p -> p.getName()))
.values()
.stream()
//cut short the groups to size of 1
.flatMap(group -> group.stream().limit(1))
//collect distinct users as list
.collect(Collectors.toList());
Distinct objects list can be found using:
List distinctPersons = persons.stream()
.collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person:: getName))),
ArrayList::new));
I made a generic version:
private <T, R> Collector<T, ?, Stream<T>> distinctByKey(Function<T, R> keyExtractor) {
return Collectors.collectingAndThen(
toMap(
keyExtractor,
t -> t,
(t1, t2) -> t1
),
(Map<R, T> map) -> map.values().stream()
);
}
An exemple:
Stream.of(new Person("Jean"),
new Person("Jean"),
new Person("Paul")
)
.filter(...)
.collect(distinctByKey(Person::getName)) // return a stream of Person with 2 elements, jean and Paul
.map(...)
.collect(toList())
Another library that supports this is jOOλ, and its Seq.distinct(Function<T,U>) method:
Seq.seq(persons).distinct(Person::getName).toList();
Under the hood, it does practically the same thing as the accepted answer, though.
Set<YourPropertyType> set = new HashSet<>();
list
.stream()
.filter(it -> set.add(it.getYourProperty()))
.forEach(it -> ...);
While the highest upvoted answer is absolutely best answer wrt Java 8, it is at the same time absolutely worst in terms of performance. If you really want a bad low performant application, then go ahead and use it. Simple requirement of extracting a unique set of Person Names shall be achieved by mere "For-Each" and a "Set".
Things get even worse if list is above size of 10.
Consider you have a collection of 20 Objects, like this:
public static final List<SimpleEvent> testList = Arrays.asList(
new SimpleEvent("Tom"), new SimpleEvent("Dick"),new SimpleEvent("Harry"),new SimpleEvent("Tom"),
new SimpleEvent("Dick"),new SimpleEvent("Huckle"),new SimpleEvent("Berry"),new SimpleEvent("Tom"),
new SimpleEvent("Dick"),new SimpleEvent("Moses"),new SimpleEvent("Chiku"),new SimpleEvent("Cherry"),
new SimpleEvent("Roses"),new SimpleEvent("Moses"),new SimpleEvent("Chiku"),new SimpleEvent("gotya"),
new SimpleEvent("Gotye"),new SimpleEvent("Nibble"),new SimpleEvent("Berry"),new SimpleEvent("Jibble"));
Where you object SimpleEvent looks like this:
public class SimpleEvent {
private String name;
private String type;
public SimpleEvent(String name) {
this.name = name;
this.type = "type_"+name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
And to test, you have JMH code like this,(Please note, im using the same distinctByKey Predicate mentioned in accepted answer) :
#Benchmark
#OutputTimeUnit(TimeUnit.SECONDS)
public void aStreamBasedUniqueSet(Blackhole blackhole) throws Exception{
Set<String> uniqueNames = testList
.stream()
.filter(distinctByKey(SimpleEvent::getName))
.map(SimpleEvent::getName)
.collect(Collectors.toSet());
blackhole.consume(uniqueNames);
}
#Benchmark
#OutputTimeUnit(TimeUnit.SECONDS)
public void aForEachBasedUniqueSet(Blackhole blackhole) throws Exception{
Set<String> uniqueNames = new HashSet<>();
for (SimpleEvent event : testList) {
uniqueNames.add(event.getName());
}
blackhole.consume(uniqueNames);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(MyBenchmark.class.getSimpleName())
.forks(1)
.mode(Mode.Throughput)
.warmupBatchSize(3)
.warmupIterations(3)
.measurementIterations(3)
.build();
new Runner(opt).run();
}
Then you'll have Benchmark results like this:
Benchmark Mode Samples Score Score error Units
c.s.MyBenchmark.aForEachBasedUniqueSet thrpt 3 2635199.952 1663320.718 ops/s
c.s.MyBenchmark.aStreamBasedUniqueSet thrpt 3 729134.695 895825.697 ops/s
And as you can see, a simple For-Each is 3 times better in throughput and less in error score as compared to Java 8 Stream.
Higher the throughput, better the performance
I would like to improve Stuart Marks answer. What if the key is null, it will through NullPointerException. Here I ignore the null key by adding one more check as keyExtractor.apply(t)!=null.
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> keyExtractor.apply(t)!=null && seen.add(keyExtractor.apply(t));
}
This works like a charm:
Grouping the data by unique key to form a map.
Returning the first object from every value of the map (There could be multiple person having same name).
persons.stream()
.collect(groupingBy(Person::getName))
.values()
.stream()
.flatMap(values -> values.stream().limit(1))
.collect(toList());
The easiest way to implement this is to jump on the sort feature as it already provides an optional Comparator which can be created using an element’s property. Then you have to filter duplicates out which can be done using a statefull Predicate which uses the fact that for a sorted stream all equal elements are adjacent:
Comparator<Person> c=Comparator.comparing(Person::getName);
stream.sorted(c).filter(new Predicate<Person>() {
Person previous;
public boolean test(Person p) {
if(previous!=null && c.compare(previous, p)==0)
return false;
previous=p;
return true;
}
})./* more stream operations here */;
Of course, a statefull Predicate is not thread-safe, however if that’s your need you can move this logic into a Collector and let the stream take care of the thread-safety when using your Collector. This depends on what you want to do with the stream of distinct elements which you didn’t tell us in your question.
There are lot of approaches, this one will also help - Simple, Clean and Clear
List<Employee> employees = new ArrayList<>();
employees.add(new Employee(11, "Ravi"));
employees.add(new Employee(12, "Stalin"));
employees.add(new Employee(23, "Anbu"));
employees.add(new Employee(24, "Yuvaraj"));
employees.add(new Employee(35, "Sena"));
employees.add(new Employee(36, "Antony"));
employees.add(new Employee(47, "Sena"));
employees.add(new Employee(48, "Ravi"));
List<Employee> empList = new ArrayList<>(employees.stream().collect(
Collectors.toMap(Employee::getName, obj -> obj,
(existingValue, newValue) -> existingValue))
.values());
empList.forEach(System.out::println);
// Collectors.toMap(
// Employee::getName, - key (the value by which you want to eliminate duplicate)
// obj -> obj, - value (entire employee object)
// (existingValue, newValue) -> existingValue) - to avoid illegalstateexception: duplicate key
Output - toString() overloaded
Employee{id=35, name='Sena'}
Employee{id=12, name='Stalin'}
Employee{id=11, name='Ravi'}
Employee{id=24, name='Yuvaraj'}
Employee{id=36, name='Antony'}
Employee{id=23, name='Anbu'}
Here is the example
public class PayRoll {
private int payRollId;
private int id;
private String name;
private String dept;
private int salary;
public PayRoll(int payRollId, int id, String name, String dept, int salary) {
super();
this.payRollId = payRollId;
this.id = id;
this.name = name;
this.dept = dept;
this.salary = salary;
}
}
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collector;
import java.util.stream.Collectors;
public class Prac {
public static void main(String[] args) {
int salary=70000;
PayRoll payRoll=new PayRoll(1311, 1, "A", "HR", salary);
PayRoll payRoll2=new PayRoll(1411, 2 , "B", "Technical", salary);
PayRoll payRoll3=new PayRoll(1511, 1, "C", "HR", salary);
PayRoll payRoll4=new PayRoll(1611, 1, "D", "Technical", salary);
PayRoll payRoll5=new PayRoll(711, 3,"E", "Technical", salary);
PayRoll payRoll6=new PayRoll(1811, 3, "F", "Technical", salary);
List<PayRoll>list=new ArrayList<PayRoll>();
list.add(payRoll);
list.add(payRoll2);
list.add(payRoll3);
list.add(payRoll4);
list.add(payRoll5);
list.add(payRoll6);
Map<Object, Optional<PayRoll>> k = list.stream().collect(Collectors.groupingBy(p->p.getId()+"|"+p.getDept(),Collectors.maxBy(Comparator.comparingInt(PayRoll::getPayRollId))));
k.entrySet().forEach(p->
{
if(p.getValue().isPresent())
{
System.out.println(p.getValue().get());
}
});
}
}
Output:
PayRoll [payRollId=1611, id=1, name=D, dept=Technical, salary=70000]
PayRoll [payRollId=1811, id=3, name=F, dept=Technical, salary=70000]
PayRoll [payRollId=1411, id=2, name=B, dept=Technical, salary=70000]
PayRoll [payRollId=1511, id=1, name=C, dept=HR, salary=70000]
Late to the party but I sometimes use this one-liner as an equivalent:
((Function<Value, Key>) Value::getKey).andThen(new HashSet<>()::add)::apply
The expression is a Predicate<Value> but since the map is inline, it works as a filter. This is of course less readable but sometimes it can be helpful to avoid the method.
Building on #josketres's answer, I created a generic utility method:
You could make this more Java 8-friendly by creating a Collector.
public static <T> Set<T> removeDuplicates(Collection<T> input, Comparator<T> comparer) {
return input.stream()
.collect(toCollection(() -> new TreeSet<>(comparer)));
}
#Test
public void removeDuplicatesWithDuplicates() {
ArrayList<C> input = new ArrayList<>();
Collections.addAll(input, new C(7), new C(42), new C(42));
Collection<C> result = removeDuplicates(input, (c1, c2) -> Integer.compare(c1.value, c2.value));
assertEquals(2, result.size());
assertTrue(result.stream().anyMatch(c -> c.value == 7));
assertTrue(result.stream().anyMatch(c -> c.value == 42));
}
#Test
public void removeDuplicatesWithoutDuplicates() {
ArrayList<C> input = new ArrayList<>();
Collections.addAll(input, new C(1), new C(2), new C(3));
Collection<C> result = removeDuplicates(input, (t1, t2) -> Integer.compare(t1.value, t2.value));
assertEquals(3, result.size());
assertTrue(result.stream().anyMatch(c -> c.value == 1));
assertTrue(result.stream().anyMatch(c -> c.value == 2));
assertTrue(result.stream().anyMatch(c -> c.value == 3));
}
private class C {
public final int value;
private C(int value) {
this.value = value;
}
}
Maybe will be useful for somebody. I had a little bit another requirement. Having list of objects A from 3rd party remove all which have same A.b field for same A.id (multiple A object with same A.id in list). Stream partition answer by Tagir Valeev inspired me to use custom Collector which returns Map<A.id, List<A>>. Simple flatMap will do the rest.
public static <T, K, K2> Collector<T, ?, Map<K, List<T>>> groupingDistinctBy(Function<T, K> keyFunction, Function<T, K2> distinctFunction) {
return groupingBy(keyFunction, Collector.of((Supplier<Map<K2, T>>) HashMap::new,
(map, error) -> map.putIfAbsent(distinctFunction.apply(error), error),
(left, right) -> {
left.putAll(right);
return left;
}, map -> new ArrayList<>(map.values()),
Collector.Characteristics.UNORDERED)); }
I had a situation, where I was suppose to get distinct elements from list based on 2 keys.
If you want distinct based on two keys or may composite key, try this
class Person{
int rollno;
String name;
}
List<Person> personList;
Function<Person, List<Object>> compositeKey = personList->
Arrays.<Object>asList(personList.getName(), personList.getRollno());
Map<Object, List<Person>> map = personList.stream().collect(Collectors.groupingBy(compositeKey, Collectors.toList()));
List<Object> duplicateEntrys = map.entrySet().stream()`enter code here`
.filter(settingMap ->
settingMap.getValue().size() > 1)
.collect(Collectors.toList());
A variation of the top answer that handles null:
public static <T, K> Predicate<T> distinctBy(final Function<? super T, K> getKey) {
val seen = ConcurrentHashMap.<Optional<K>>newKeySet();
return obj -> seen.add(Optional.ofNullable(getKey.apply(obj)));
}
In my tests:
assertEquals(
asList("a", "bb"),
Stream.of("a", "b", "bb", "aa").filter(distinctBy(String::length)).collect(toList()));
assertEquals(
asList(5, null, 2, 3),
Stream.of(5, null, 2, null, 3, 3, 2).filter(distinctBy(x -> x)).collect(toList()));
val maps = asList(
hashMapWith(0, 2),
hashMapWith(1, 2),
hashMapWith(2, null),
hashMapWith(3, 1),
hashMapWith(4, null),
hashMapWith(5, 2));
assertEquals(
asList(0, 2, 3),
maps.stream()
.filter(distinctBy(m -> m.get("val")))
.map(m -> m.get("i"))
.collect(toList()));
In my case I needed to control what was the previous element. I then created a stateful Predicate where I controled if the previous element was different from the current element, in that case I kept it.
public List<Log> fetchLogById(Long id) {
return this.findLogById(id).stream()
.filter(new LogPredicate())
.collect(Collectors.toList());
}
public class LogPredicate implements Predicate<Log> {
private Log previous;
public boolean test(Log atual) {
boolean isDifferent = previouws == null || verifyIfDifferentLog(current, previous);
if (isDifferent) {
previous = current;
}
return isDifferent;
}
private boolean verifyIfDifferentLog(Log current, Log previous) {
return !current.getId().equals(previous.getId());
}
}
My solution in this listing:
List<HolderEntry> result ....
List<HolderEntry> dto3s = new ArrayList<>(result.stream().collect(toMap(
HolderEntry::getId,
holder -> holder, //or Function.identity() if you want
(holder1, holder2) -> holder1
)).values());
In my situation i want to find distinct values and put their in List.

Java8 Method chaining for Single object without Stream/Optional?

I felt it easiest to capture my question with the below example. I would like to apply multiple transformations on an object (in this case, they all return same class, Number, but not necessarily). With an Optional (Method 3) or Stream (Method 4), I can use the .map elegantly and legibly. However, when used with a single object, I have to either just make an Optional just to use the .map chaining (with a .get() in the end), or use Stream.of() with a findFirst in the end, which seems like unnecessary work.
[My Preference]: I prefer methods 3 & 4, as they seem better for readability than the pre-java8 options - methods 1 & 2.
[Question]: Is there a better/neater/more preferable/more elegant way of achieving the same than all the methods used here? If not, what method would you use?
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Tester {
static class Number {
private final int value;
private Number(final int value) {
this.value = value;
}
public int getValue() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
}
private static Number add(final Number number, final int val) {
return new Number(number.getValue() + val);
}
private static Number multiply(final Number number, final int val) {
return new Number(number.getValue() * val);
}
private static Number subtract(final Number number, final int val) {
return new Number(number.getValue() - val);
}
public static void main(final String[] args) {
final Number input = new Number(1);
System.out.println("output1 = " + method1(input)); // 100
System.out.println("output2 = " + method2(input)); // 100
System.out.println("output3 = " + method3(input)); // 100
System.out.println("output4 = " + method4(input)); // 100
processAList();
}
// Processing an object - Method 1
private static Number method1(final Number input) {
return subtract(multiply(add(input, 10), 10), 10);
}
// Processing an object - Method 2
private static Number method2(final Number input) {
final Number added = add(input, 10);
final Number multiplied = multiply(added, 10);
return subtract(multiplied, 10);
}
// Processing an object - Method 3 (Contrived use of Optional)
private static Number method3(final Number input) {
return Optional.of(input)
.map(number -> add(number, 10))
.map(number -> multiply(number, 10))
.map(number -> subtract(number, 10)).get();
}
// Processing an object - Method 4 (Contrived use of Stream)
private static Number method4(final Number input) {
return Stream.of(input)
.map(number -> add(number, 10))
.map(number -> multiply(number, 10))
.map(number -> subtract(number, 10))
.findAny().get();
}
// Processing a list (naturally uses the Stream advantage)
private static void processAList() {
final List<Number> inputs = new ArrayList<>();
inputs.add(new Number(1));
inputs.add(new Number(2));
final List<Number> outputs = inputs.stream()
.map(number -> add(number, 10))
.map(number -> multiply(number, 10))
.map(number -> subtract(number, 10))
.collect(Collectors.toList());
System.out.println("outputs = " + outputs); // [100, 110]
}
}
The solution is to build your methods into your Number class. For example:
static class Number {
// instance variable, constructor and getter unchanged
public Number add(final int val) {
return new Number(getValue() + val);
}
// mulitply() and subtract() in the same way
// toString() unchanged
}
Now your code becomes very simple and readable:
private static Number method5(final Number input) {
return input
.add(10)
.multiply(10)
.subtract(10);
}
You may even write the return statement on one line if you prefer:
return input.add(10).multiply(10).subtract(10);
Edit: If you can't change the Number class, my personal taste would be for method2. Using Optional or Stream would be misuse or at least misplaced and could easily confuse your reader. If you insist, write your own Mandatory class, like Optional except it always holds a value, which makes it simpler. For my part I wouldn't bother.

Java 8 stream reduce Map

I have a LinkedHashMap which contains multiple entries. I'd like to reduce the multiple entries to a single one in the first step, and than map that to a single String.
For example:
I'm starting with a Map like this:
{"<a>"="</a>", "<b>"="</b>", "<c>"="</c>", "<d>"="</d>"}
And finally I want to get a String like this:
<a><b><c><d></d></c></b></a>
(In that case the String contains the keys in order, than the values in reverse order. But that doesn't really matter, I'd like an general solution)
I think I need map.entrySet().stream().reduce(), but I have no idea what to write in the reduce method, and how to continue.
Since you're reducing entries by concatenating keys with keys and values with values, the identity you're looking for is an entry with empty strings for both key and value.
String reduceEntries(LinkedHashMap<String, String> map) {
Entry<String, String> entry =
map.entrySet()
.stream()
.reduce(
new SimpleImmutableEntry<>("", ""),
(left, right) ->
new SimpleImmutableEntry<>(
left.getKey() + right.getKey(),
right.getValue() + left.getValue()
)
);
return entry.getKey() + entry.getValue();
}
Java 9 adds a static method Map.entry(key, value) for creating immutable entries.
here is an example about how I would do it :
import java.util.LinkedHashMap;
public class Main {
static String result = "";
public static void main(String [] args)
{
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("<a>", "</a>");
map.put("<b>", "</b>");
map.put("<c>", "</c>");
map.put("<d>", "</d>");
map.keySet().forEach(s -> result += s);
map.values().forEach(s -> result += s);
System.out.println(result);
}
}
note: you can reverse values() to get d first with ArrayUtils.reverse()

how to return value from tryAdvance method in Java8's spliterator?

I am new to Java 8 and trying to understand the splitIterator feature of java8.
I have written below code, my requirement is whenever I call get(); the get method should return me one value from itr3; Is it possible to get the same? and how?
public class TestSplitIterator {
static List<Integer> list = new ArrayList<Integer>();
public static void main(String args[]) {
for (int i = 0; i < 100; i++) {
list.add(i);
}
// below method call should return only one value whenever i call it;
get(list);
}
private static int get(List<Integer> list) {
Collections.sort(list, Collections.reverseOrder());
System.out.println(list);
Spliterator<Integer> itr1 = list.spliterator();
Spliterator<Integer> itr2 = itr1.trySplit();
Spliterator<Integer> itr3 = itr2.trySplit();
// i want to return value from itr3 whenever get(List list ic called)
}
}
If I don't misunderstand you. you need a collector object that collect the elements in a spliterator. for example:
Integer[] collector = new Integer[1];
boolean exist = itr3.tryAdvance(value -> collector[0] = value);
System.out.println(collector[0]);
OR collect all of the elements in a spliterator by using another List, for example:
List<Integer> collector = new ArrayList<>();
while (itr3.tryAdvance(collector::add)) ;
System.out.println(collector);

Sorting Arraylist by an object variable

Any ideas on how to apply Collections.sort method to sort my arraylist by priority of each grocItem object within the itemData ArrayList?
public class GroceryProgram {
private final static int GROC_SIZE = 6;
private final List<ItemData> itemData = new ArrayList<ItemData>();
private void setUpList() {
Scanner keyboard = new Scanner(System.in);
for (int i = 0; i < GROC_SIZE; i++) {
System.out.print("\nEnter item name (" + i + ") : ");
String name = keyboard.next();
System.out.print("\nEnter the price of item (" + i + ") : ");
double cost = keyboard.nextDouble();
System.out.print("\nEnter Priority Number (" + i + ") : ");
int priority = keyboard.nextInt();
ItemData grocItem = new ItemData(name, cost, priority);
itemData.add(grocItem); // add grocery items to itemData ArrayList
Collections.sort(grocItem);
for (Int priority : priority) {
System.out.println(integer);
Call sort() with a Comparator. For example, a Comparator in ascending-order of priority could look like this.
Collections.sort( items, new Comparator<ItemData>() {
public int compare (ItemData o1, ItemData o2) {
int comp = o1.getPriority() - o2.getPriority();
return comp;
}
});
PS: 'itemData' is bad variable naming -- it would refer to a single item, not a list. 'groceryItems', 'stockItems' or 'itemList' would be better.
Variable names should enable you to speak in meaningful, clear, concise English about your software.
Hope this helps.
Could you use Collections.sort(List list, Comparator c) to deal with this? You could simply do the following :
Collections.sort(itemData, new Comparator() {
public int compare(Object o1, Object o2) {
// Return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
}
}
You can use custom comparator as below:
Collections.sort(itemData ,new PriorityComparator());
//print sorted arraylist,it will print the data in ascending order (low priority->high priority).feel free to modify if you want to go for descending order
System.out.println(itemData );
PriorityComparator class definition:
private static class PriorityComparator implements Comparator{
#Override
public int compare(ItemData object1, ItemData object2) {
return (object1.priority< object2.priority) ? -1: (object1.priority> object2.priority) ? 1:0 ;
}
}
Reference:
how-to-sort-arraylist-in-java-example
I hope it will be helpful !!

Resources