adding elements while iterating [duplicate] - java

This question already has answers here:
java.util.ConcurrentModificationException thrown when adding to List
(2 answers)
Closed 1 year ago.
I have a list of concrete objects. While iterating over this list, I'm trying to update an object from it by adding values and I'm getting of course a ConcurentModificationException:
What are my alternatives? Thank you and appreciate the help. I'm using Java 11.
import lombok.Data;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class Test {
public static void main(String[] args) throws IOException {
List<Person> myList = new ArrayList<>();
List<Hobby> hobbies = new ArrayList<>();
Hobby h1 = new Hobby("SKI");
Hobby h2 = new Hobby("reading");
hobbies.add(h1);
hobbies.add(h2);
Person p = new Person("R", hobbies);
Person p1 = new Person("M", hobbies);
myList.add(p);
myList.add(p1);
myList
.forEach(currentElement -> {
if (Objects.isNull(currentElement.getHobbies())) {
currentElement.setHobbies(Collections.singletonList(new Hobby("NOTHING")));
} else {
currentElement.getHobbies()
.forEach(hobby -> {
if (hobby.getMyHobby().equals("SKI")) {
currentElement.getHobbies().add(new Hobby("SAILING"));
} else {
hobby.getMyHobby().toLowerCase();
}
});
}
});
}
#Data
static
class Person {
String name;
List<Hobby> hobbies;
public Person(String name, List<Hobby> hobbies) {
this.name = name;
this.hobbies = hobbies;
}
}
#Data
static class Hobby {
String myHobby;
public Hobby(String myHobby) {
this.myHobby = myHobby;
}
}
}

You can iterate over the indexes instead:
for (int i = 0; i < currentElement.getHobbies().size(); i++) {
Hobby hobby = currentElement.getHobbies().get(i);
if (hobby.getMyHobby().equals("SKI")) {
currentElement.getHobbies().add(new Hobby("SAILING"));
} else {
hobby.getMyHobby().toLowerCase(); // sic
}
}

Related

Java: Arraylist of Array

I want to make an arraylist of an array of 2 elements. So, I have unknown rows and known columns (i.e. 2).
E.g. [{name1, ID1}, {name2, ID2}, ...]
I also have to return this arraylist.
I tried using
ArrayList<arr> alist = new ArrayList<arr>();
but don't know how to proceed.
Please advise.
When you define a ArrayList must use a class. In this case, you can use a class Person:
class Person {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Then, we can define a ArrayList of Persons:
ArrayList<Person> array = new ArrayList<Person>();
array.get(0).getId();
array.get(0).getName();
I have put here two simple ways to do it. However, you can think of many more such ways.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Main {
public static void main(String[] a) {
List<String[]> list = new ArrayList<>();
String[] arr;
arr = new String[2];
arr[0] = "name1";
arr[1] = "ID1";
list.add(arr);
arr = new String[2];
arr[0] = "name2";
arr[1] = "ID2";
list.add(arr);
// Test
for (String[] arrElem : list) {
System.out.println(arrElem[0] + "\t" + arrElem[1]);
}
// Another option is to create a list of maps
List<Map<String, String>> list2 = new ArrayList<>();
Map<String, String> map = null;
map = new HashMap<>();
map.put("name1", "ID1");
list2.add(map);
map = new HashMap<>();
map.put("name2", "ID2");
list2.add(map);
// Test
for (Map<String, String> mapElem : list2) {
System.out.println(mapElem);
}
}
}
Output:
name1 ID1
name2 ID2
{name1=ID1}
{name2=ID2}

JXPath : how to query all keys from a map

I am trying to query a property of all items in a map.
I can do it with a collection, but it does not work for map.
I have tries many variation, but did not find a way to get all ids of objects in map.
See complete code example below.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.jxpath.JXPathContext;
public class TestMap {
public static void main(String[] args) {
Person p = createPerson(1);
p.foes = new HashMap<>();
p.foes.put("a", createPerson(2));
p.foes.put("b", createPerson(3));
p.friends = new ArrayList<>();
p.friends.add(createPerson(4));
p.friends.add(createPerson(5));
//works
Iterator<Object> friendsId = JXPathContext.newContext(p).iterate("friends/id");
friendsId.forEachRemaining(o -> System.out.println(o));
// works
Iterator<Object> foesId = JXPathContext.newContext(p).iterate("foes/a/id");
foesId.forEachRemaining(o -> System.out.println(o));
// does not works :(
foesId = JXPathContext.newContext(p).iterate("foes/id");
foesId.forEachRemaining(o -> System.out.println(o));
}
private static Person createPerson(Integer id) {
Person p = new Person();
p.setId(id);
return p;
}
public static class Person {
private Integer id;
private List<Person> friends;
private Map<String, Person> foes;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<Person> getFriends() {
return friends;
}
public void setFriends(List<Person> friends) {
this.friends = friends;
}
public Map<String, Person> getFoes() {
return foes;
}
public void setFoes(Map<String, Person> foes) {
this.foes = foes;
}
}
}
https://commons.apache.org/proper/commons-jxpath/users-guide.html#Map_Element_Access
found it : "foes/*/id" works.
A bit obvious

How to get string array from json object in deserialize method

I have some json object
{
"name": "John",
"age": 29,
"bestFriends": [
"Stan",
"Nick",
"Alex"
]
}
Here is my implementation of JsonDeserializer:
public class CustomDeserializer implements JsonDeserializer<Person>{
#Override
public Person deserialize(JsonElement json, Type type, JsonDeserializationContext cnxt){
JsonObject object = json.getAsJsonObject();
String name = new String(object.get("name").getAsString());
Integer age = new Integer(object.get("age").getAsInt());
String bestFriends[] = ?????????????????????????????????
return new Person(name, age, bestFriends);
}
}
How to get string array from json object here using GSON library?
Thanks a lot!
For the deserializer you can just loop over the ArrayNode and add the values to your String[] one after another.
ArrayNode friendsNode = (ArrayNode)object.get("bestFriends");
List<String> bestFriends = new ArrayList<String>();
for(JsonNode friend : friendsNode){
bestFriends.add(friend.asText());
}
//if you require the String[]
bestFriends.toArray();
Try this this will work for you. Thanks.
package test;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
class ID{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Override
public String toString() {
return "ID [id=" + id + "]";
}
}
public class Test {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
String jsonText = "{\"id\" : \"A001\"}";
//convert to object
try {
ID id = mapper.readValue(jsonText, ID.class);
System.out.println(id);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I want to thank all who responded on my question and in the same time i find my decision (which is below) as the most fitting answer. Because i don't need to use any other libraries except GSON.
When i asked my question i didn't know that com.google.gson.TypeAdapter is more efficient instrument than JsonSerializer/JsonDeserializer.
And here below i have found decision for my problem:
package mytypeadapter;
import com.google.gson.Gson;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
public class Main {
static class Person{
String name;
int age;
String[] bestFriends;
Person() {}
Person(String name, int population, String... cities){
this.name = name;
this.age = population;
this.bestFriends = cities;
}
}
public static void main(String[] args) {
class PersonAdapter extends TypeAdapter<Person>{
#Override
public Person read (JsonReader jsonReader) throws IOException{
Person country = new Person();
List <String> cities = new ArrayList<>();
jsonReader.beginObject();
while(jsonReader.hasNext()){
switch(jsonReader.nextName()){
case "name":
country.name = jsonReader.nextString();
break;
case "age":
country.age = jsonReader.nextInt();
break;
case "bestFriends":
jsonReader.beginArray();
while(jsonReader.hasNext()){
cities.add(jsonReader.nextString());
}
jsonReader.endArray();
country.bestFriends = cities.toArray(new String[0]);
break;
}
}
jsonReader.endObject();
return country;
}
#Override
public void write (JsonWriter jsonWriter, Person country) throws IOException{
jsonWriter.beginObject();
jsonWriter.name("name").value(country.name);
jsonWriter.name("age").value(country.age);
jsonWriter.name("bestFriends");
jsonWriter.beginArray();
for(int i=0;i<country.bestFriends.length;i++){
jsonWriter.value(country.bestFriends[i]);
}
jsonWriter.endArray();
jsonWriter.endObject();
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(Person.class, new PersonAdapter())
.setPrettyPrinting()
.create();
Person person, personFromJson;
person = new Person ("Vasya", 29, "Stan", "Nick", "Alex");
String json = gson.toJson(person);
personFromJson = new Person();
personFromJson = gson.fromJson(json, personFromJson.getClass());
System.out.println("Name = "+ personFromJson.name);
System.out.println("Age = "+ personFromJson.age);
for(String friend : personFromJson.bestFriends){
System.out.println("Best friend "+ friend);
}
}
}

Get child hierarchy path till parent in java

I have a scenario to get a child hierarchy structure of a field till parent for doing field level validations.
Can someone provide some solution.
Pojo classes
Student.java
package com.poc.next.validations;
import java.util.ArrayList;
import java.util.List;
public class Student {
private String studentName;
private List<Subject> subjects;
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public List<Subject> getSubjects() {
if (subjects == null) {
return new ArrayList<>();
}
return subjects;
}
public void setSubjects(List<Subject> subjects) {
this.subjects = subjects;
}
}
Subject.java
package com.poc.next.validations;
import java.util.ArrayList;
import java.util.List;
public class Subject {
private String subjectName;
private List<RevisionMarks> revisionMarks;
public String getSubjectName() {
return subjectName;
}
public void setSubjectName(String subjectName) {
this.subjectName = subjectName;
}
public List<RevisionMarks> getRevisionMarks() {
if (revisionMarks == null) {
return new ArrayList<>();
}
return revisionMarks;
}
public void setRevisionMarks(List<RevisionMarks> revisionMarks) {
this.revisionMarks = revisionMarks;
}
}
RevisionMarks.java
package com.poc.next.validations;
public class RevisionMarks {
private Integer mark;
private String revision;
public Integer getMark() {
return mark;
}
public void setMark(Integer mark) {
this.mark = mark;
}
public String getRevision() {
return revision;
}
public void setRevision(String revision) {
this.revision = revision;
}
}
Now we are adding a validation to check whether the given mark in RevisionMarks class in valid or not. if it is equal to zero I have to add it to error dto and send it back to UI. The challenge here is i have to provide the field name dynamic in hierarchy like "subjects[0].revisionMarks[0].mark".
Main class
RevisionValidation.java
package com.poc.next.validations;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class RevisionValidation {
public static void main(String[] args) {
Student student = populateStudentData();
Iterator<Subject> iterator = student.getSubjects().iterator();
while (iterator.hasNext()) {
Subject subject = (Subject) iterator.next();
RevisionMarks revisionMarks = subject.getRevisionMarks().get(0);
System.out.println(revisionMarks.getMark());
if (revisionMarks.getMark() == 0) {
ErrorDTO errorDTO = new ErrorDTO(true, "Invalid Marks", "Error", "subjects[0].revisionMarks[0].mark",
"invalid_mark");
System.out.println(errorDTO);
}
}
}
private static Student populateStudentData() {
List<RevisionMarks> revisionMarks = new ArrayList<>();
RevisionMarks revisionMark = new RevisionMarks();
revisionMark.setMark(0);
revisionMark.setRevision("Test 1");
revisionMarks.add(revisionMark);
List<Subject> subjects = new ArrayList<>();
Subject subject = new Subject();
subject.setSubjectName("CS");
subject.setRevisionMarks(revisionMarks);
subjects.add(subject);
Student student = new Student();
student.setStudentName("Sample");
student.setSubjects(subjects);
return student;
}
}
How can I dynamically create the fieldpath like "subjects[0].revisionMarks[0].mark".
Any suggestions are welcome. Thanks in advance.
Use a counter:
int counter = 0;
Iterator<Subject> iterator = student.getSubjects().iterator();
while (iterator.hasNext()) {
Subject subject = (Subject) iterator.next();
RevisionMarks revisionMarks = subject.getRevisionMarks().get(0);
System.out.println(revisionMarks.getMark());
if (revisionMarks.getMark() == 0) {
ErrorDTO errorDTO = new ErrorDTO(true, "Invalid Marks", "Error", "subjects[" + counter + "].revisionMarks[0].mark",
"invalid_mark");
System.out.println(errorDTO);
}
++counter;
}
I would suggest to use JSR3 validation instead of reinventing wheel.
https://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/
You can add necessary annotations for each field in your POJO and add #Valid annotation to let validator check nested POJO objects.
The link
https://www.beyondjava.net/blog/how-to-invoke-jsr-303-bean-validation-programmatically/ shows how to call the validator programmatically.
With the validation you can provide any messages and localize them, and the xpaths are built automatically pointing problems in POJO or nested POJOs.

Sort JList by name

What I am doing is getting elements from a map and adding them onto a JList to display on a GUI. I want to know how to sort the names alphabetically.
private void refreshShopsList() {
gameShopsJList.setModel(new javax.swing.AbstractListModel<String>() {
public int getSize() {
return ShopsLoader.getShops().size();
}
public String getElementAt(int i) {
return getShopByIndex(i).getName();
}
});
}
private Shop getShopByIndex(int index) {
Iterator<Entry<String, Shop>> it = ShopsLoader.getShops().entrySet().iterator();
int count = -1;
while(it.hasNext()) {
Entry<String, Shop> entry = it.next();
count++;
if (count == index)
return entry.getValue();
}
return null;
}
/**
* The map of the shops
*/
private static final Map<String, Shop> shops = new HashMap<String, Shop>();
public static Map<String, Shop> getShops() {
return shops;
}
Here is a little example, which sorts your shop names.
The ShopComparator class does the sorting task:
package model;
import java.util.Comparator;
public class ShopComparator implements Comparator<Shop> {
#Override
public int compare(Shop o1, Shop o2) {
return o1.getName().compareTo(o2.getName());
}
}
The Shop class, as simple as possible:
package model;
public class Shop {
private int id;
private String name;
public Shop(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And the main app:
package model;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
public class App {
public static void main(String[] args) {
Map<String, Shop> shops = new HashMap<String, Shop>();
Shop s1 = new Shop(1, "Apus Drugstore");
Shop s2 = new Shop(2, "DM");
Shop s3 = new Shop(3, "Kaufhof");
Shop s4 = new Shop(4, "Moes Traverne");
shops.put("one", s3);
shops.put("two", s4);
shops.put("three", s1);
shops.put("four", s2);
for(Shop s : shops.values()) {
System.out.println(s.getName());
}
ShopComparator sc = new ShopComparator();
TreeSet<Shop> sortedShops = new TreeSet<>(sc);
sortedShops.addAll(shops.values());
for(Shop s : sortedShops) {
System.out.println(s.getName());
}
}
}
First output, unsorted:
Moes Traverne
Kaufhof
Apus Drugstore
DM
and the sorted output.
Apus Drugstore
DM
Kaufhof
Moes Traverne
Algorithm:
get all values from JList, convert them to strings, store in array
sort the array
set new values to JList.
code:
JList jl = new JList(new Object[]{4.5,1,"Hi!"});
ListModel model = jl.getModel();
String[] strings = new String[model.getSize()];
for(int i=0;i<strings.length;i++){
strings[i]=model.getElementAt(i).toString();
}
Arrays.sort(strings);
jl.setListData(strings);
see about Comparator if you need to sort array in any other order.

Categories

Resources