Rewrite existing code with Java 8 Lambda - java

I have one object, two conditions and need to convert it into a list.
SelectItem has getLabel and getValue
Casting problem
Expect Result -> List of Employees
Object refer to class (Example: Employees.class)
The code looks like:
public static final List<Employees> onFilterObjectFromSelectItems(final String query,final List<SelectItem> selectItemList) {
final List <Employees>result = new ArrayList<>();
for (SelectItem sl : selectItemList) {
Employees x = (Employees) sl.getValue();
if (x.getCode.contains(query) || x.getName.contains(query)) {
result.add(x);
}
}
return result;
}

Try following code.
List<Employees> EmployeeList = selectItemList.stream()
.filter(x-> x.getCode().contains(query) || x.getName().contains(query))
.map(e->(Employees)e.getValue())
.collect(Collectors.toList());

Related

Java sort array of objects by integer field and if those are identical then sort by another integer value

I have a java problem in relation too sorting an arrayList of objects.
I have already figured out to sort an arrayList of object by specific fields, which can be seen in the following code
public void printPrioritized() {
System.out.println("Prioritized todo:");
System.out.println("-----------------");
List<Task> sortedList = new ArrayList<Task>(taskList);
Collections.sort(sortedList, new Comparator<Task>() {
public int compare(Task o1, Task o2) {
return Integer.valueOf(o1.getPriority()).compareTo(o2.getPriority());
}
});
sortedList.forEach((e) -> {
System.out.println(e);
});
My problem is that if to object fields are the same then i am supposed to sort by another value. This means that i have to sort by an value of 1 to 4 (getPriority() method), but if two objects for instance both are 2 then i have to sort by another value which for instance could be time. Hope someone can help.
Assuming your Task class looks something like:
class Task {
int priority;
int anotherValue;
// getters, setters ...
}
you can create custom compartors and chain them while sorting, example:
List<Task> myList = new ArrayList<>();
Comparator<Task> byPriority = (t1,t2) -> Integer.compare(t1.getPriority(), t2.getPriority());
Comparator<Task> byAnotherValue = (t1,t2) -> Integer.compare(t1.getAnotherValue(), t2.getAnotherValue());
myList.sort(byPriority.thenComparing(byAnotherValue));
OR
you can combine those sortings ->
List<Task> myList = new ArrayList<>();
Comparator<Task> sortedComparator = (t1,t2) -> {
if (t1.getPriority() != t2.getPriority()) {
return Integer.compare(t1.getPriority(), t2.getPriority());
}
else if (t1.getAnotherValue() != t2.getAnotherValue()) {
return Integer.compare(t1.getAnotherValue(), t2.getAnotherValue());
}
};
myList.sort(sortedComparator);
Try to customize the compare method.
e.g.
if(o1.getPriority() != o2.getPriority())
return Integer.valueOf(o1.getPriority()).compareTo(o2.getPriority());
if(o1.getTime() != o2.getTime())
return Integer.valueOf(o1.getTime()).compareTo(o2.getTime());
return 0; //they are equal with all fields

If else with java 8 Lambda

I want to replace conventional if else with lambda. Consider following highlighted code, is there some simple way to have this represented with Lambda ?
public class IfElseLambda {
public static void main(String[] args) {
String value = null;
DataObj data = new DataObj();
List<DataObj> dataObjs = data.getDataObjs();
***if (dataObjs != null) {
value = dataObjs.stream().map(dataObject -> getValue(dataObject)).filter(Objects::nonNull).findFirst().orElse(null);
} else {
value = getValue(data);
}***
}
public static String getValue(DataObj dataObj) {
return "Get value from dataObj";
}
}
class DataObj {
List<DataObj> dataObjs;
public List<DataObj> getDataObjs() {
return dataObjs;
}
public void setDataObjs(List<DataObj> dataObjs) {
this.dataObjs = dataObjs;
}
}
One thing you can do is to change the null list to something which results in the same output:
List<DataObj> dataObjs = Optional.ofNullable(data.getDataObjs()).orElse(Collections.singletonList(data));
dataObjs will now be a list with a single element in the case that data.getDataObjs() is null.
Now you don't need the if/else:
value = dataObjs.stream().map(dataObject -> getValue(dataObject)).filter(Objects::nonNull).findFirst().orElse(null);
I your aim is to isolate the logic of your if-else, and potentially allowing it to be replaced, maybe you could do the following :
Your lambda take as input your data list, and gives you back a String value. Therefore, you can use a java.util.Function interface, like this:
Function<List<DataObj>, String> extractor = dataList
-> dataList == null? Stream.of(DEFAULT_DATA_OBJ) : dataList.stream()
.map(dataObject -> getValue(dataObject))
.filter(Objects::nonNull)
.findFirst()
.orElse(null)
Note, you still have a ternary operator (Do not see how you could do without it, because if your list can be null, you cannot even use Stream.concat to protect from empty-list). However, with that construct, the logic of your ternary operator is replaceable if you make the extractor function replaceable in your code.
Exemple:
public static void main(String... args) {
final List<DataObj> dataList = ...;
final DataObj defaultValue = ...;
Function<List<DataObj>, String> extractor = dataList
-> dataList == null? Stream.of(defaultValue) : dataList.stream()
.map(dataObject -> getValue(dataObject))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
doStuff(dataList, extractor);
// Now, if you want to change your extraction logic, do
doStuff(dataList, whatever -> "Return a constant title");
}
public static void doStuff(final List<DataObj> dataList, final Function<List<DataObj, String> titleExtractor) {
// Do stuff here
}

get all object from 1 list of 1 list by stream in java 8?

I have 2 classes, this:
public class TimeCardResponse {
private String login;
List<TimeCardDetail> timeCardDetails;
}
and this:
public TimeCardDetail(String workingDay, Float workingTime) {
this.workingDay = workingDay;
this.workingTime = workingTime;
}
input : a List<TimeCardResponse>
I want to get all workingDay of class TimeCardDetail in a List<String> and using Stream in Java 8.
List<String> workingDays = a.stream().map(TimeCardResponse::getTimeCardDetails)
.filter(x-> Objects::nonNull)
.flatMap(List::stream)
.map(TimeCardDetail::getWorkingDay).collect(toList());
Assuming you have some a getWorkingDay method:
List<String> workDays = timeCardDetails.stream()
.map(TimeCardDetail::getWorkingDay)
.filter(Objects::nonNull) //filter out null values
.collect(Collectors.toList());
Which will return a List<String> of the work days of the time Cards

JAVA 8 : need to perform List iteration in stream and convert list of another object

I have a list of object List(Item) from service.
I want to convert the List(Item) list to DB table ItemEntity object using Java 8 stream. In that List(Item) Item-> have VarietyList, if the VarietyList(itemVariety) have data then need to create that many ItemEntity object. if the VarietyList(itemVariety) is empty then need to create one ItemEntity object.
Below Java for each code works perfectly, i need this code in JAVA 8 Stream function.
List<Item> itemList = from some services;
List<ItemEntity> itemEnt= new ArrayList();
for (Item item : itemsList) {
if (CollectionUtils.isNotEmpty(item.getVarietyList())) {
for (ItemVariety itemVariety : item.getVarietyList()) {
itemEnt.add(loadItemData(item , itemVariety));
}
} else {
itemEnt.add(loadItemData(item, null));
}
}
private ItemEntity loadItemData(Item itemType, ItemVariety itemVariety) {
ItemEntity itemEntity = new ItemEntity();
itemEntity.setName(itemType.getName());
if (itemVariety != null) {
itemEntity.setVarietyName(itemVariety .getName());
}
return cropEntity;
}
Please suggest me the best way in JAVA8
Generally speaking, a for loop over a list of instances of class A that creates an instance of a class B for each item in the original list can be turned into
List<A> as = .... ;
List<B> = as.stream().map(a -> createB(a)).collect(Collectors.toList());
where
private B createB(A a) {
//returns new B() based on given a
}
When for each item in the original list you can create more than one instance of B, you for loop can be turned into
List<A> as = .... ;
List<B> = as
.stream()
.flatMap(a -> CreateBs(a))
.collect(Collectors.toList());
where
private Stream<B> createBs(A a) {
// returns Stream<B> based on a
}
You are in the second scenario, so you createBs(A) is
private Stream<ItemEntity> createItemEntity(Item item) {
return item.getVarietyList().isEmpty() ?
Stream.of(loadItemData(item, null)) :
item.getVarietyList().stream(x -> mapItemVarietyToItemEntity(item, x));
}
private ItemEntity mapItemVarietyToItemEntity(Item item, ItemVariety variety) {
loadItemData(item, variety);
}
I can't run the code above at the moment, but I hope it can help you toward the solution you're searching for.
If you really wants to use the stream api you could do it something like below, but IMO it's much more readable in plain old java.
List<ItemEntity> itemEnt = itemsList.stream()
.flatMap(item -> {
return CollectionUtils.isNotEmpty(item.getVarietyList())
? item.getVarietyList.stream().map(variety -> loadItemData(item, variety))
: Stream.of(loadItemData(item, null))
}).collect(Collectors.toList());
private ItemEntity loadItemData(Item itemType, ItemVariety itemVariety) {
ItemEntity itemEntity = new ItemEntity();
itemEntity.setName(itemType.getName());
if (itemVariety != null) {
itemEntity.setVarietyName(itemVariety .getName());
}
return cropEntity;
}

passing in two lambda functions

I want to pass two lambda expressions (or something similar, I'm still getting familiar with all the terminology) into a method; the first one will get a list of items, and the second one will retrieve one Integer object from (each one of) those items.
So I want to have a method something like this:
private List<Integer> getRecentList(List<Integer> searchParams,
Function<List<Integer>, List<Integer>> listGetter,
Supplier<Integer> idGetter)
{
List<Object> objectList = listGetter.apply(searchParams);
List<Integer> idList = new ArrayList<>();
for (Object o: objectList)
{
idList.add(idGetter.get());
}
return idList;
}
and call it something like this:
List<Integer> idList = setRecentList(searchParams,
(a) -> serviceOne.getItemList(a),
Item::getItemId);
So the first function is one called on an instance variable that the called method will have access to, and the second function is an instance method on any one of the objects returned as a list by the first function.
But the (eclipse) compiler doesn't like Item::getItemId, with or without parentheses at the end.
Do I just have a syntax thing wrong, or is there something else wrong with this idea?
Edit after many helpful comments -- thanks to you all!
I have one problem left. I've now got a method that I think does what I want, but I'm not sure how to pass the second expression to call it. Here is the method:
private List<Integer> getRecentList(List<Integer> salesCodeIdList,
Function<List<Integer>, List> listGetter,
Function<Object, Integer> idGetter
) {
List<Object> objectList = listGetter.apply(salesCodeIdList);
List<Integer> idList = new ArrayList<>();
for (Object o : objectList) {
idList.add(idGetter.apply((o)));
}
return idList;
}
AFAIK, I have to leave the second List raw in the getter spec, since different getters will return different types of objects in their lists.
But I still don't know how to invoke it -- I want to pass a method that gets an id from a particular instance of object, i.e., I want to pass a getter on the ID of one of the objects returned by the listGetter. That will be different types of objects on different calls. How would I invoke that?
To go back to examples, if I had a Supplier class with getSupplierId(), and a Vendor class with getVendorId(), and I cannot change those classes, can I pass in the correct method to invoke on the objects in the list depending on which getter retrieved the list?
A likely reason why you get the error is hidden inside the implementation of your method:
private List<Integer> getRecentList(List<Integer> searchParams,
Function<List<Integer>, List<Object>> listGetter,
Supplier<Integer> idGetter)
{
List<Object> objectList = listGetter.apply(searchParams);
List<Integer> idList = new ArrayList<>();
for (Object o: objectList)
{
idList.add(idGetter.get()); // <<<<<==== Here
}
return idList;
}
Note how o from the for loop is not used in the call, indicating that idGetter would get you an ID out of thin air. That's of course is not true: you need to pass an item to idGetter, which means that the call should be
idList.add(idGetter.apply(o));
(from the comment) I can't cast within the method, I don't know what type of object to cast to there.
which in turn means that idGetter should be Function<Object,Integer>:
for (Object o: objectList)
{
idList.add(idGetter.apply(o));
}
Since you would like to reuse the same function for lists of different types, the call would have to use a lambda that performs the cast at the caller, i.e. at the point where you know the type:
List<Integer> idList = setRecentList(searchParams,
(a) -> serviceOne.getItemList(a),
(o) -> ((Item)o).getItemId());
Item::getItemId is not a Supplier<Integer>. A Supplier<Integer> is a lambda function that takes no arguments and returns an Integer. But Item::getItemId would require an Item to get the ID from.
Here is probably what you want. Note I've changed your method signature to match the idea that you're getting IDs from items.
class Item {
int id;
Item (int i) {
id = i;
}
int getItemId() {
return id;
}
}
private static List<Integer> getRecentList(List<Integer> searchParams,
Function<List<Integer>, List<Item>> listGetter,
Function<Item, Integer> idGetter)
{
List<Item> itemList = listGetter.apply(searchParams);
List<Integer> idList = new ArrayList<>();
for (Item item: itemList)
{
idList.add(idGetter.apply(item));
}
return idList;
}
Edit: If you want this to handle multiple kinds of Items, and they all have IDs, you can do something like the following. First, define an interface to represent the fact that your different kinds of Items all have IDs:
interface ItemWithId {
abstract int getItemId();
}
class ItemA implements ItemWithId {
int id;
ItemA(int i) {
id = i;
}
public int getItemId() {
return id;
}
}
class ItemB implements ItemWithId {
int id;
ItemB(int i) {
id = i;
}
public int getItemId() {
return id;
}
}
Then, your method should use ItemWithId instead of Item:
private List<Integer> getRecentList(List<Integer> searchParams,
Function<List<Integer>, List<ItemWithId>> listGetter,
Function<ItemWithId, Integer> idGetter)
{
List<ItemWithId> itemList = listGetter.apply(searchParams);
List<Integer> idList = new ArrayList<>();
for (ItemWithId item: itemList)
{
idList.add(idGetter.apply(item));
}
return idList;
}
Finally, you can call this by casting an ItemA or ItemB to an ItemWithId:
List<Integer> idList = getRecentList(searchParams,
(a) -> getItemList(a),
(item) -> ((ItemWithId) item).getItemId());
Another edit: Ok, so you can't change ItemA or ItemB. You can still make it work:
class ItemA {
int id;
ItemA(int i) {
id = i;
}
public int getItemIdA() {
return id;
}
}
class ItemB {
int id;
ItemB(int i) {
id = i;
}
public int getItemIdB() {
return id;
}
}
private List<Integer> getRecentList(List<Integer> searchParams,
Function<List<Integer>, List<Object>> listGetter,
Function<Object, Integer> idGetter)
{
List<Object> itemList = listGetter.apply(searchParams);
List<Integer> idList = new ArrayList<>();
for (Object item: itemList)
{
idList.add(idGetter.apply(item));
}
return idList;
}
List<Integer> idList = getRecentList(searchParams,
(a) -> getItemList(a),
(item) -> ((ItemA) item).getItemIdA());
// or
List<Integer> idList = getRecentList(searchParams,
(a) -> getItemList(a),
(item) -> ((ItemB) item).getItemIdB());

Categories

Resources