There are four records in the above table; how can i get result which will have unique id and get the latest record sorted by creation time using Java 8 streams.
In this example; I want to see only two records like this:
6838322 45210 2018-03-08 06:07
and
6838320 45209 2018-03-08 05:50
yourObjects.stream()
.collect(Collectors.toMap(
YourObject::getId,
YourObject::getCreationTime,
BinaryOperator.maxBy(Comparator.comparing(Function.identity())
))
where YourObject is actually the object in java that you have and getCreationTime returns a Date that is Comparable.
You can sort the stream by creationtime, and apply equality of records on id (so that you can use distinct). Following is the code:
public class StreamStuff {
public static void main(String[] args) {
List<Data> datas = Arrays.asList(new Data(6838322, new Date()), new Data(6838320, new Date(1520574131111L)),
new Data(6838320, new Date(1520574136940L)), new Data(6838320, new Date(324324353999L)));
datas.stream()
.sorted((d1, d2) -> d2.creationTime.compareTo(d1.creationTime))
.distinct()
.forEach(System.out::println);
}
}
class Data {
int id;
Date creationTime;
public Data(int id, Date creationTime) {
super();
this.id = id;
this.creationTime = creationTime;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Data other = (Data) obj;
if (id != other.id)
return false;
return true;
}
#Override
public String toString() {
return "Data [id=" + id + ", creationTime=" + creationTime + "]";
}
}
Related
I want to store Objects in the Hash map as key and while Retrieving time i want a ascending order based on Employee id.and i dont want to use comparator or comaprable interfaces just sorting based on hashcode and equals method is it possible.
public class Employee {
private String name;
private int id;
public String getName() {
return name;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
// result = prime * result + ((name == null) ? 0 : name.hashCode());
System.out.println("hashcode value :::"+result + "id :::"+id);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Employee other = (Employee) obj;
if (id != other.id) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
package info.test;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MainClass {
public static void main(String[] args) {
Employee e1 = new Employee();
e1.setId(2);
e1.setName("name");
Employee e2 = new Employee();
e2.setId(35);
e2.setName("name");
Employee e3 = new Employee();
e3.setId(4);
e3.setName("name");
Employee e4 = new Employee();
e4.setId(3);
e4.setName("name");
Map<Employee, String> linkedHashMap = new HashMap<Employee,String>();
linkedHashMap.put(e1, "e");
linkedHashMap.put(e2, "e");
linkedHashMap.put(e3, "e");
linkedHashMap.put(e4, "e");
Set<Employee> keySet = linkedHashMap.keySet();
for(Employee e:keySet){
//System.out.println(e.getId());
}
}}
its work some samples like
if give ids like 2 55 4 3 and output is 2 3 4 55
and for some samples its not working
2 35 4 3 and output 2 35 3 4
You were so close. This
Map<Employee, String> linkedHashMap = new HashMap<Employee,String>();
should be LinkedHashMap which preserved insertion order like
Map<Employee, String> linkedHashMap = new LinkedHashMap<>();
If it should be sorted in natural order use a TreeMap like
Map<Employee, String> linkedHashMap = new TreeMap<>();
I have a HashMap where the key is a class and value is an integer. I need to check if an object of the class already exists in the map. I use containsKey(), but for some reason it does not work when I include attribute sideDish in the equals() and hashCode(). Here is my code for the classes:
OrderItem class:
#ToString
#Entity
#Table(name="OrderItem")
public class OrderItem implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Getter #Setter
private Long id;
#ManyToOne
#Getter #Setter
private Food food;
#ManyToMany
#Getter #Setter
private List<SideDish> sideDishes;
public OrderItem() {}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((food == null) ? 0 : food.hashCode());
result = prime * result + ((sideDishes == null) ? 0 : sideDishes.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OrderItem other = (OrderItem) obj;
if (food == null) {
if (other.food != null)
return false;
} else if (!food.equals(other.food))
return false;
if (sideDishes == null) {
if (other.sideDishes != null)
return false;
} else if (!sideDishes.equals(other.sideDishes))
return false;
return true;
}
}
Food class:
#ToString
#Entity
#Table(name="Food")
public class Food implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Getter #Setter
private Long id;
#Column(nullable = false, unique = true)
#NotNull(message = "Name cannot be null.")
#Getter #Setter
private String name;
#ManyToMany
#Getter #Setter
private List<SideDish> sidedishes;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((foodtype == null) ? 0 : foodtype.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Food other = (Food) obj;
if (foodtype == null) {
if (other.foodtype != null)
return false;
} else if (!foodtype.equals(other.foodtype))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
SideDish class:
#Entity
#ToString(exclude= {"id","dishtype"})
#Table(name="SideDish")
public class SideDish implements Serializable, Comparable<SideDish>{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Getter #Setter
private Long id;
#Getter #Setter
#Column(nullable = false, unique = true)
private String name;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SideDish other = (SideDish) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
For some reason, if I removethe sideDish attribute from equals() and hashCode() in the OrderItem class, it works perfectly.
But I also need sideDish to be checked as part of the object identity.
Here is how I use it:
HashMap<OrderItem, Integer> orderItemsToSend = new HashMap<OrderItem, Integer>();
for (Order order : orders) {
for (OrderItem orderItem : order.getOrderItems()) {
int numSimilarOrders = getNumOfSimilarOrders(orderItem, orders);
if(!orderItemsToSend.containsKey(orderItem)) {
orderItemsToSend.put(orderItem, numSimilarOrders);
}else {
System.out.println("Vec je dodat item koji isti kao: " + orderItem.getFood().getName());
}
}
}
In your OrderItem class, both your hashCode() and equals() depend on the property List<SideDish> sideDishes.
Thus, if sideDishes changes, so does the hashCode() (and so does equality).
A HashMap uses both hashCode() and equals() to store and find the object which is the key. It uses a concept called "hash buckets". If you put a key into a HashMap, and then the hashCode() changes, that object will be in the wrong hash bucket, and you won't be able to find it again.
A key is something which is used for lookup purposes - that's what the word "key" means. An important quality of a key, whether in a database, or a hashmap, is immutability. So in Java, that means an object which changes its hashCode() makes for a bad key.
It's a bit like if a file system did lookups by the hash of the filename, but then you changed the filename, but it didn't update the hash. You'd only find the file by doing a lookup with the old name.
This simple test program will illustrate the point.
We store 2 objects in a HashMap, and then change the hashCode(). The map still contains both objects, but now one of them cannot be found or used for lookup.
The solution is use some simple immutable object as the key, such as a Long of its database ID.
Sample output is below the code.
public class HashTest {
static class Hashable {
String name;
#Override
public int hashCode() {
return ((name == null) ? 0 : name.hashCode());
}
#Override
public boolean equals(Object object) {
return (object instanceof Hashable) && equals((Hashable) object);
}
private boolean equals(Hashable that) {
return Objects.equals(this.name, that.name);
}
#Override
public String toString() {
// Use identityHashCode() so we can really see which object is which
return "[" + name + ":" + System.identityHashCode(this) + "]";
}
}
public static void main(String[] args) {
Hashable one = new Hashable();
one.name = "one";
Hashable two = new Hashable();
two.name = "one";
print(one, two);
two.name = "two";
print(one, two);
HashMap<Hashable, Integer> map = new HashMap<>();
map.put(one, 1);
map.put(two, 2);
find(map, one, two);
one.name = "two"; // Let's confuse things
print(one, two);
find(map, one, two);
}
private static void print(Hashable one, Hashable two) {
System.out.print("Names:" + one.name + ":" + two.name);
System.out.print("\tHashcodes:" + one.hashCode() + ":" + two.hashCode());
System.out.println("\tEquals:" + one.equals(two));
}
private static void find(HashMap<Hashable, Integer> map, Hashable one, Hashable two) {
System.out.print(map);
System.out.print("\tFound: " + map.get(one));
System.out.println("\tFound: " + map.get(two));
}
}
Sample output:
Names:one:one Hashcodes:110182:110182 Equals:true
Names:one:two Hashcodes:110182:115276 Equals:false
{[one:366712642]=1, [two:1829164700]=2} Found: 1 Found: 2
Names:two:two Hashcodes:115276:115276 Equals:true
{[two:366712642]=1, [two:1829164700]=2} Found: 2 Found: 2
I am trying to create a HashMap, that adds objects to a line, if they are not already present in this line. This is how I check it:
if (!waiting.containsKey(p)) {
waiting.put(current, p);
current++;
}
Where p is our object, which is stored with an Integer. However, when I run this code. It will store the same object several times under different integers, how can this be prevented?
thats because you call containsKey with the object and not the key:
parameter must be an Integer key
Integer lKey = 0;
if(!waiting.containsKey(lKey)){
waiting.put(current, p);
current++;
}
if your object has an identifier use this identifier for the map.
if(!waiting.containsKey(p.getId())){
waiting.put(p.getId(), p);
current++;
}
otherwise use containsValue():
if(!waiting.containsValue(p)){
waiting.put(current, p);
current++;
}
but then you have to overwrite the equals method.
If you want to use an object as a key, you can override the equals() and hashCode() methods to return and compare the id of the object.
Driver.java
import java.util.HashMap;
import java.util.Map;
public class Driver {
public static void main(String[] args) {
Map<MyObject, Integer> map = new HashMap<MyObject, Integer>();
map.put(new MyObject(1000L, "One"), 1);
map.put(new MyObject(1001L, "Two"), 2);
map.put(new MyObject(1002L, "Three"), 3);
Long id = 1001L;
System.out.println(contains(map, id)); // true
System.out.println(get(map, id)); // 2
}
public static <T, U> boolean contains(Map<T, U> map, T obj) {
return map.containsKey(obj);
}
public static boolean contains(Map<MyObject, Integer> map, Long id) {
return contains(map, new MyObject(id, ""));
}
public static <T, U> U get(Map<T, U> map, T obj) {
return map.get(obj);
}
public static Integer get(Map<MyObject, Integer> map, Long id) {
return get(map, new MyObject(id, ""));
}
}
MyObject.java
public class MyObject {
private Long id;
private String name;
protected Long getId() {
return id;
}
protected void setId(Long id) {
this.id = id;
}
protected String getName() {
return name;
}
protected void setName(String name) {
this.name = name;
}
public MyObject(Long id, String name) {
this.id = id;
this.name = name;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
MyObject other = (MyObject) obj;
if (id == null) {
if (other.id != null) return false;
} else if (!id.equals(other.id)) return false;
return true;
}
#Override
public String toString() {
return "MyObject { id : " + id + ", name : " + name + "}";
}
}
I have a DropDownChoice :
DropDownChoice timePeriod = new DropDownChoice("timePeriod", Arrays.asList(new TimePeriod(1, "Weekly"), new TimePeriod(2, "Bi-Weekly"), new TimePeriod(3, "Semi-Monthly"), new TimePeriod(4, "Monthly"), new TimePeriod(5, "Yearly")), new IChoiceRenderer() {
private static final long serialVersionUID = 10102L;
#Override
public String getIdValue(Object object, int index) {
return ((TimePeriod) object).getId() + "";
}
#Override
public Object getDisplayValue(Object object) {
return ((TimePeriod) object).getPeriodType();
}
});
timePeriod.setNullValid(false);
My question is:
How to set the selected index to 2 or any other?
How to remove first default blank option?
Thank you.
You should be able to set the selected index by using a PropertyModel instead of hard-coding the values of the dropdown. I can't test at the moment, but it would be something like
String timePeriodValue = "Bi-Weekly";
DropDownChoice timePeriod = new DropDownChoice("timePeriod",
new PropertyModel(this, "timePeriodValue"),
Arrays.asList(/* your options */),
new IChoiceRenderer() {
// ...
// Again, this is pseudocode only
As a bonus, the very act of setting a default value should eliminate the blank option problem.
DropDownChoice has a constructor which accepts the default value.
Or in your code you can add timePeriod.setModel(Model.of(new TimePeriod(2, "Bi-Weekly")))
I guess TimePeriod has proper #equals() and #hashCode() implementations.
About the blank option: see org.apache.wicket.markup.html.form.AbstractSingleSelectChoice.isNullValid()
Lord Torgamus and martin-g thank you both of you. I did a small test. And it is working perfectly. As Lord Torgamus indicated,
#SuppressWarnings({ "unchecked", "rawtypes", "serial" })
public class MyPage extends WebPage {
public MyPage() {
add(new MyForm("form"));
}
private class MyForm extends Form {
public MyForm(String id) {
super(id);
setOutputMarkupPlaceholderTag(true);
setModel(new Model(new FormModel()));
final DropDownChoice timePeriod = new DropDownChoice("timePeriod", new PropertyModel(getModel(), "timePeriod"), Arrays.asList(new TimePeriod(1, "Weekly"), new TimePeriod(2, "Bi-Weekly"), new TimePeriod(3, "Semi-Monthly"), new TimePeriod(4, "Monthly"), new TimePeriod(5, "Yearly")), new IChoiceRenderer() {
private static final long serialVersionUID = 10102L;
#Override
public String getIdValue(Object object, int index) {
return ((TimePeriod) object).getId() + "";
}
#Override
public Object getDisplayValue(Object object) {
return ((TimePeriod) object).getPeriodType();
}
});
timePeriod.setNullValid(false);
add(timePeriod);
timePeriod.setOutputMarkupPlaceholderTag(true);
timePeriod.add(new AjaxFormComponentUpdatingBehavior("onChange") {
#Override
protected void onUpdate(AjaxRequestTarget target) {
MyForm form = (MyForm) timePeriod.getParent();
FormModel formModel = (FormModel) form.getModelObject();
formModel.setTimePeriod(new TimePeriod(4, "Monthly"));
form.setModel(new Model(formModel));
target.addComponent(form);
}
});
}
#Override
public void onSubmit() {
System.out.println(getModelObject());
}
}
private class FormModel implements Serializable {
private TimePeriod timePeriod = new TimePeriod(2, "Bi-Weekly");
public FormModel() {
}
public TimePeriod getTimePeriod() {
return timePeriod;
}
public void setTimePeriod(TimePeriod timePeriod) {
this.timePeriod = timePeriod;
}
#Override
public String toString() {
return "FormModel [timePeriod=" + timePeriod + "]";
}
}
private class TimePeriod implements Serializable {
private int id;
private String periodType;
public TimePeriod(int id, String periodType) {
super();
this.id = id;
this.periodType = periodType;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPeriodType() {
return periodType;
}
public void setPeriodType(String periodType) {
this.periodType = periodType;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + id;
result = prime * result + ((periodType == null) ? 0 : periodType.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TimePeriod other = (TimePeriod) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (id != other.id)
return false;
if (periodType == null) {
if (other.periodType != null)
return false;
} else if (!periodType.equals(other.periodType))
return false;
return true;
}
private LoginPage getOuterType() {
return LoginPage.this;
}
#Override
public String toString() {
return "TimePeriod [id=" + id + ", periodType=" + periodType + "]";
}
}
}
The above code is provided for other users as it might be helpful and I wrote it for testing purpose so all the classes are written in one .java file although it is not advisable.
Thank you.
I have a type of object which contains id and points information.
I have a list of that object. I need to add each new id, if any old id enters i need to add 1 to the points to the old entry .then add to the list.
Here is my pojo
public class Salary {
int id;
int points;
public Salary(int id, int points) {
this.id = id;
this.points = points;
}
// getters and setters
}
Here is the situation
class info{
public static void main(String[] args) {
List<Salary> salaries = new ArrayList<>();
salaries.add(new Salary(1,100));
salaries.add(new Salary(2,200));
Salary newSalary = new Salary(1,200);
}
}
Since the id is same i need to make 100 to 101 and update the list , how can i do that with java 8 ?
In your Salary class you should implement equals and hashcode as follows:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Salary other = (Salary) obj;
if (id != other.id)
return false;
return true;
}
and in your main method add this:
Salary newSalary = new Salary(1,200);
for(Salary s: salaries){
if(s.equals(newSalary)){
s.points++;
}
}