This question already has answers here:
How to call a method in another class of the same package?
(8 answers)
Closed 2 years ago.
first I have three classes:
Data.java:
public class Data {
public static List<String> studentdataget(){
List<String> studentData = new ArrayList<String>();
// Format:
// Name ; Number ; Subject
studentData.add("Quee;810283;MathI");
studentData.add("Hor;812227;Math I");
studentData.add("Oper;810369;Math II");
studentData.add("Graf;811090;MathI");
studentData.add("Ingri;811911;MathI");
Student.java:
public class Student {
private static String name = "";
private static int number = 0;
private static String subject = "";
public Student(String name, int number, String subject) {
this.name = name;
this.number = number;
this.subject = subject;
}
public static String getnumber(String segs) {
return number;
}
public static int getnumber(String segs) {
return number;
}
public static String getName() {
return name;
}
public void setsubject(String subject) {
this.subject = subject;
}
public void setnumber(int number) {
this.number = number;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
String returnString = name + " (" + number + "), Subject: " + subject;
return returnString;
}
}
main.java:
public class main {
public static void main(String[] args) {
String path = "Name;number;subject";
String[] segs = path.split( Pattern.quote( ";" ) );
//System.out.println( (segs[2]));
HashMap<String, String> studentData = new HashMap<String, String>();
studentData.put(segs[1],segs[2]);
for (Map.Entry<String, String> pair: studentData.entrySet()) {
System.out.format("key: %s, value: %s\n", pair.getKey(), pair.getValue());
}
for(Map.Entry<String, String> pair: studentData.entrySet()) {
}
}
}
So the question is how can I put in my second for loop the list from my Data.class?
I want to display only the number and the subject is this possible ?
I have try so many ways and no one is getting me to the solution .. I hope someone can give me a solution
To access the studentData method from another class, you can use this notation Data.studentdataget(); since studentdataget() is static.
You just split() on ; in each entry of yout list to split them into [Quee, 810283, MathI]. Therefore you can use the last two indexes to get the desired data.
This assumes all the data in studentData remains uniform.
public static void main(String[] args) {
List<String> students = Data.studentdataget(); // access Data here
HashMap<String, String> classes = new HashMap<>();
// fill our map from the data found in Data.studentdataget
for (String student: students) {
String[] arr = student.split(";"); // split string into array on each ;
classes.put(arr[1], arr[2]); // fill map based on student data set
}
// print the map
for (Map.Entry<String, String> entry : classes.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
For example, I have two Arrays converted into ArrayList which is firstName and lastName. I want to sort these two lists using the first names, the last name will follow through the first names.
Expected output:
firstNameList = {Andrew, Johnson, William}
lastNameList = {Wiggins, Beru, Dasovich};
My Initial Program:
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
String [] firstName = {William, Johnson, Andrew};
String [] lastName = {Dasovich, Beru, Wiggins};
//Will convert arrays above into list.
List <String> firstNameList= new ArrayList<String>();
List <String> lastNameList= new ArrayList<String>();
//Conversion
Collections.addAll(firstNameList, firstName);
Collections.addAll(lastNameList, lastName);
Domain
As I have stated in my comment, I would recommend using a Person-POJO to bind firstName and lastName in a semantic way:
class Person {
public static final String PERSON_TO_STRING_FORMAT = "{f: %s, l: %s}";
private final String firstName;
private final String lastName;
private Person(final String firstName, final String lastName) {
this.firstName = Objects.requireNonNull(firstName);
this.lastName = Objects.requireNonNull(lastName);
}
public static Person of(final String firstName, final String lastName) {
return new Person(firstName, lastName);
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
#Override
public String toString() {
return String.format(PERSON_TO_STRING_FORMAT, getFirstName(), getLastName());
}
}
To convert two String[]s firstNames and lastNames into a List<Person>, one can provide a method:
public static List<Person> constructPersons(
final String[] firstNames,
final String[] lastNames) {
if (firstNames.length != lastNames.length) {
throw new IllegalArgumentException("firstNames and lastNames must have same length");
}
return IntStream.range(0, firstNames.length)
.mapToObj(index -> Person.of(firstNames[index], lastNames[index]))
.collect(Collectors.toCollection(ArrayList::new));
}
A remark on this method: Here, we use collect(Collectors.toCollection(...)) instead of collect(Collectors.toList()) to have some control with respect to list mutability since we are going to sort the list.
From here on there are two general routes: Either one makes Person comparable by public class Person implements Comparable<Person> or one writes a Comparator<Person>. We will discuss both possibilities.
Challenge
The goal is to sort Person-objects. The primary criteria for sorting is the first name of the person. If two persons have equal first names, then they should be ordered by their last names. Both first- and last name are String-objects and should be ordered in lexicographical order, which is String's natural order.
Solution 1: Implementing Comparable<Person> on Person
The logic to implement the comparison is straight-forward:
Compare the firstNames of two persons using equals(...).
If they are equal, compare the lastNames using compareTo(...) and return the result.
Otherwise, compare the firstNames with compareTo(...) and return the result.
The corresponding method would then look like this:
public class Person implements Comparable<Person> {
...
#Override
public final int compareTo(final Person that) {
if (Objects.equals(getFirstName(), that.getFirstName())) {
return getLastName().compareTo(that.getLastName());
}
return getFirstName().compareTo(that.getFirstName());
}
...
}
While not strictly necessary, it is recommended that the natural ordering of a class (i.e. the Comparable-implementation) is consistent with its equals(...)-implementation. Since this is not the case right now, I would recommend overriding equals(...) and hashCode():
public class Person implements Comparable<Person> {
...
#Override
public final boolean equals(Object thatObject) {
if (this == thatObject) {
return true;
}
if (thatObject == null || getClass() != thatObject.getClass()) {
return false;
}
final Person that = (Person) thatObject;
return Objects.equals(getFirstName(), that.getFirstName()) &&
Objects.equals(getLastName(), that.getLastName());
}
#Override
public final int hashCode() {
return Objects.hash(getFirstName(), getLastName());
}
...
}
The following code demonstrates how to create and order a List<Person> from two String[]:
final List<Person> persons = constructPersons(
new String[]{"Clair", "Alice", "Bob", "Alice"},
new String[]{"Clear", "Wonder", "Builder", "Ace"}
);
Collections.sort(persons);
System.out.println(persons);
Solution 2: Implementing a Comparator<Person>
A traditional implementation of a comparator realizing the sort comparison given in the challenge-section may look like this:
class PersonByFirstNameThenByLastNameComparator implements Comparator<Person> {
public static final PersonByFirstNameThenByLastNameComparator INSTANCE =
new PersonByFirstNameThenByLastNameComparator();
private PersonByFirstNameThenByLastNameComparator() {}
#Override
public int compare(final Person lhs, final Person rhs) {
if (Objects.equals(lhs.getFirstName(), rhs.getFirstName())) {
return lhs.getLastName().compareTo(rhs.getLastName());
}
return lhs.getFirstName().compareTo(rhs.getFirstName());
}
}
A example call may look like this:
final List<Person> persons = constructPersons(
new String[]{"Clair", "Alice", "Bob", "Alice"},
new String[]{"Clear", "Wonder", "Builder", "Ace"}
);
persons.sort(PersonByFirstNameThenByLastNameComparator.INSTANCE);
System.out.println(persons);
With Java 8, the construction of a Comparator has been simplified through the Comparator.comparing-API. To define a Comparator realizing the order given in section Challenge with the Comparator.comparing-API, we only need one line of code:
Comparator.comparing(Person::getFirstName)
.thenComparing(Person::getLastName)
The following code demonstrates how this Comparator is used to sort a List<Person>:
final List<Person> persons = constructPersons(
new String[]{"Clair", "Alice", "Bob", "Alice"},
new String[]{"Clear", "Wonder", "Builder", "Ace"}
);
persons.sort(Comparator.comparing(Person::getFirstName)
.thenComparing(Person::getLastName));
System.out.println(persons);
Closing Notes
A MRE is available on Ideone.
I would question the initial design decision to split up first- and last names into two separate arrays. I opted to not include the method List<Person> constructPersons(String[] firstNames, String[] lastNames) in class Person since this is just adapter-code. It should be contained in some mapper, but is not a functionality that is existential for Person.
You can do this by merging the two arrays into one stream of Names, with first and last name, sort that stream and then recreate the two lists.
String[] firstName = {"William", "Johnson", "Andrew"};
String[] lastName = {"Dasovich", "Beru", "Wiggins"};
final var sortedNames = IntStream.range(0, firstName.length)
.mapToObj(i -> new Name(firstName[i], lastName[i]))
.sorted(Comparator.comparing(n -> n.firstName))
.collect(Collectors.toList());
final var sortedFirstNames = sortedNames.stream()
.map(n -> n.firstName)
.collect(Collectors.toList());
final var sortedLastNames = sortedNames.stream()
.map(n -> n.lastName)
.collect(Collectors.toList());
As highlighted by comments , your problem is you are using two different lists for names and surnames so the ordering process for the two types of data are totally unrelated. A possible solution is creation of a new class Person including two fields name and surname and implementing Comparable interface like below:
public class Person implements Comparable<Person> {
public String firstName;
public String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
#Override
public String toString() {
return "Person [firstName=" + firstName + ", lastName=" + lastName + "]";
}
#Override
public int compareTo(Person o) {
return this.firstName.compareTo(o.firstName);
}
public static void main(String[] args) {
Person[] persons = { new Person("William", "Dasovich"),
new Person("Johnson", "Beru"),
new Person("Andrew", "Wiggins") };
Collections.sort(Arrays.asList(persons));
for (Person person : persons) {
System.out.println(person);
}
}
}
The Collections.sort method provides the order of the Person array by firstName.
Because the firstName and lastName are connected to each other, you should create a class to model them as such. Let's call this class Person:
class Person {
private final String firstName;
private final String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
// Add toString, equals and hashCode as well.
}
Now, create a list of persons instead:
List<Person> persons = Arrays.asList(
new Person("Andrew", "Wiggins"),
new Person("Johnson", "Beru"),
new Person("William", "Dasovich"));
Now, to sort it, you can use the sorted method on a stream with a comparator. This will create a new List<Person> which will be sorted. The Comparator.comparing function will let you pick which property of the Person class that you want to sort on. Something like this:
List<Person> sortedPersons = persons.stream()
.sorted(Comparator.comparing(Person::getFirstName))
.collect(Collectors.toList());
A TreeSet could do it:
(using a Person class as suggested by Turing85)
import java.util.Set;
import java.util.TreeSet;
public class PersonTest {
private static class Person implements Comparable<Person> {
private final String firstName;
private final String lastName;
public Person(final String firstName, final String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
#Override
public int compareTo(final Person otherPerson) {
return this.firstName.compareTo(otherPerson.firstName);
}
#Override
public String toString() {
return this.firstName + " " + this.lastName;
}
}
public static void main(final String[] args) {
final Set<Person> people = new TreeSet<>();
/**/ people.add(new Person("William", "Dasovich"));
/**/ people.add(new Person("Johnson", "Beru"));
/**/ people.add(new Person("Andrew", "Wiggins"));
people.forEach(System.out::println);
}
}
but Streams & a somewhat simpler Person class might do too:
import java.util.stream.Stream;
public class PersonTest {
private static class Person {
private final String firstName;
private final String lastName;
public Person(final String firstName, final String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
#Override
public String toString() {
return this.firstName + " " + this.lastName;
}
}
public static void main(final String[] args) {
Stream.of(
new Person("William", "Dasovich"),
new Person("Johnson", "Beru" ),
new Person("Andrew", "Wiggins" ) )
.sorted ((p1,p2) -> p1.firstName.compareTo(p2.firstName))
.peek (System.out::println)
.sorted ((p1,p2) -> p1.lastName .compareTo(p2.lastName))
.forEach(System.out::println);
}
}
String[] firstName = {"William", "Johnson", "Andrew"};
String[] lastName = {"Dasovich", "Beru", "Wiggins"};
// combine the 2 arrays and add the full name to an Array List
// here using a special character to combine, so we can use the same to split them later
// Eg. "William # Dasovich"
List<String> combinedList = new ArrayList<String>();
String combineChar = " # ";
for (int i = 0; i < firstName.length; i++) {
combinedList.add(firstName[i] + combineChar + lastName[i]);
}
// Sort the list
Collections.sort(combinedList);
// create 2 empty lists
List<String> firstNameList = new ArrayList<String>();
List<String> lastNameList = new ArrayList<String>();
// iterate the combined array and split the sorted names to two lists
for (String s : combinedList) {
String[] arr = s.split(combineChar);
firstNameList.add(arr[0]);
lastNameList.add(arr[1]);
}
System.out.println(firstNameList);
System.out.println(lastNameList);
If you don't want to create DTO to keep the first names and last names together, you can use a kind of functional way based on java streams :
create couples with lists to bind those two values
sort them, base on the first name
flat the couple, in order to have a list with one dimension
String[] firstName = {"William", "Johnson", "Andrew"};
String[] lastName = {"Dasovich", "Beru", "Wiggins"};
//Will convert arrays above into list.
List<String> firstNameList = new ArrayList<String>();
List<String> lastNameList = new ArrayList<String>();
//Conversion
Collections.addAll(firstNameList, firstName);
Collections.addAll(lastNameList, lastName);
List<String> collect = firstNameList
.stream()
.map(name -> {
List<String> couple = List.of(name, lastNameList.get(0));
lastNameList.remove(0);
return couple;
})
.sorted(Comparator.comparing(l -> l.get(0)))
.flatMap(Collection::stream)
.collect(Collectors.toList());
String[] firstNames = {William, Johnson, Andrew};
String[] lastNames = {Dasovich, Beru, Wiggins};
//Will convert arrays above into list.
List<String> firstNameList = new ArrayList<String>();
List<String> lastNameList = new ArrayList<String>();
Map<String, String> lastNameByFirstName = new HashMap<>();
for (int i = 0; i < firstNames.length; i++) {
lastNameByFirstName.put(firstNames[i], lastNames[i]);
}
//Conversion
Collections.addAll(firstNameList, firstNames);
Collections.sort(firstNameList);
for (String firstName : firstNameList) {
lastNameList.add(lastNameByFirstName.get(firstName));
}
I made a Map to store the values of all tags on a SOAPMessage body, so that the keys of the Map are the node names and the values are the text contents. I have an object where I already have the fields named after the node names, what I need to do is to set their values accordingly to their map counterparts.
Say that I have a node named "Summary" on the SOAPMessage, there will be a Map key named "Summary" and also an object field named "Summary". I need the object field "Summary" to be set as the value of the Map.get("Summary").
I know I could just fill my code with setters for each of the fields, but is there an way to set the entire object from the Map?
This is the method where I created the Map.
private static Map<String, String> mapIncidentInfo(SOAPMessage soapResponse) throws SOAPException {
Map<String, String> fields = new HashMap<String, String>();
NodeList nodes = soapResponse.getSOAPBody().getFirstChild().getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
fields.put(node.getNodeName(), node.getTextContent());
}
return fields;
}
This could be used as an object class example:
public class IncidentPO {
private String Submitter;
private String Submit_Date;
private String Last_Modified_By;
private String Last_Modified_Date;
private String Status;
private String Short_Description;
public IncidentPO(String Submitter, String Submit_Date, String Last_Modified_By, String Last_Modified_Date, String Status, String Short_Description) {
this.Submitter = Submitter;
this.Submit_Date = Submit_Date;
this.Last_Modified_By = Last_Modified_By;
this.Last_Modified_Date = Last_Modified_Date;
this.Status = Status;
this.Short_Description = Short_Description;
//getters and setters here
There's no easy way (without libraries) to convert a Map to object. A direct option is to provide the Map in a constructor and have it populate itself.
public IncidentPO(Map<String, String> map) {
this.Submitter = map.get("Submitter");
this.Submit_Date = map.get("Submit_Date");
// etc
}
You can use object to json mapping then again json to object as below:
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class TestMap {
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
Map<String, String> myMmap = new HashMap<>();
myMmap.put("name", "ABC");
myMmap.put("age", "20");
myMmap.put("sex", "male");
myMmap.put("city", "madhepura");
myMmap.put("spec", "java");
ObjectMapper mapper = new ObjectMapper();
ObjectNode objectNode1 = mapper.createObjectNode();
for(String key : myMmap.keySet()) {
objectNode1.put(key, myMmap.get(key));
}
// take the value of objectNode1.toString() and create a pojo from http://www.jsonschema2pojo.org/
Person person = mapper.readValue(objectNode1.toString().getBytes(), Person.class);
System.out.println(person);
}
}
// you can use http://www.jsonschema2pojo.org to get POJO from objectNode1.toString()
// {"city":"patna","sex":"male","name":"ABC","age":"20","spec":"java"}
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"city",
"sex",
"name",
"age",
"spec"
})
class Person {
#JsonProperty("city")
private String city;
#JsonProperty("sex")
private String sex;
#JsonProperty("name")
private String name;
#JsonProperty("age")
private String age;
#JsonProperty("spec")
private String spec;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonProperty("city")
public String getCity() {
return city;
}
#JsonProperty("city")
public void setCity(String city) {
this.city = city;
}
#JsonProperty("sex")
public String getSex() {
return sex;
}
#JsonProperty("sex")
public void setSex(String sex) {
this.sex = sex;
}
#JsonProperty("name")
public String getName() {
return name;
}
#JsonProperty("name")
public void setName(String name) {
this.name = name;
}
#JsonProperty("age")
public String getAge() {
return age;
}
#JsonProperty("age")
public void setAge(String age) {
this.age = age;
}
#JsonProperty("spec")
public String getSpec() {
return spec;
}
#JsonProperty("spec")
public void setSpec(String spec) {
this.spec = spec;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
Suppose I have a class MyData.
public class Mydata(){
private String name;
private int age;
}
Now my list will be having 100 MyData objects and I want to extract only the names and prepare a new list:
List<String> nameList;
What is the best way to do that?
This would be the best option:
for (Mydata mydata : mydataList){
nameList.add(mydata.name);
}
With Java 8 you can use stream() and map() for a much more concise and clear variant:
data.stream().map(Mydata::getName).collect(Collectors.toList());
Here as a full program:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Test {
static class Mydata
{
private String name;
private int age;
public String getName() {return name;}
public int getAge() {return age;}
public Mydata(String name, int age)
{
this.name = name;
this.age = age;
}
}
public static void main(String[] args)
{
List<Mydata> data = Arrays.asList(new Mydata[] {new Mydata("Tom",10),new Mydata("Mary",20)});
//map(m->m.name) also works
List<String> nameList = data.stream().map(Mydata::getName).collect(Collectors.toList());
System.out.println(nameList);
}
}
If you don't care the sorting...
for (Mydata mydata : mydataList){
nameList.add(mydata.name);
}
If you have Java 8...
List<Mydata> mydatas = ...
List<String> names =
mydatas.stream().map(mydata -> mydata.name).collect(Collectors.toList())
What i want to do is store some instances of my class on a list and get a specific instance from that list.
This is an example of a custom class
public class Person
{
private String name;
//Several unrelevant fields here
public Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
//Several unrelevant methods here
}
And this is the code i'm currently using to get one of the instances on the list, that is on the main class.
public class Main
{
private List<Person> people = new ArrayList<Person>();
//More unrelevant fields here
public Person getPerson(String name)
{
for (Person p : people)
if (p.getName().equalsIgnoreCase(name))
return p;
return null;
}
//More unrelevant methods here
}
My question is if there's any other way to write this to increase the performance.
Use a Map whose keys are the names and whose values are the people.
HashMap is case sensitive. If you wanted case-insensitive lookups, you could use a TreeMap. My example demonstrates that people with the same name (case insensitively) overwrite each other.
import java.util.Map;
import java.util.TreeMap;
public class SoMain {
Map<String, Person> nameToPersonMap =
new TreeMap<String, Person>(String.CASE_INSENSITIVE_ORDER);
public static void main(String[] args) {
new SoMain().run(args);
}
private void run(String[] args) {
addPerson(new Person("Jim McDonald", 1));
addPerson(new Person("Jim Mcdonald", 2));
addPerson(new Person("John Smith", 3));
System.out.println("Number of people: "
+ nameToPersonMap.entrySet().size());
System.out.println("Jim McDonald id: "
+ getPerson("Jim McDonald").getPersonId());
System.out.println("John Smith id: "
+ getPerson("john smith").getPersonId());
}
private void addPerson(Person p) {
nameToPersonMap.put(p.getName(), p);
}
private Person getPerson(String name) {
return nameToPersonMap.get(name);
}
public static class Person {
private String name;
private int personId;
public Person(String name, int personId) {
this.name = name;
this.personId = personId;
}
public int getPersonId() {
return personId;
}
public String getName() {
return name;
}
}
}
As Eric mentions, you should use a HashMap, the reasoning for this is because you can look up and add data to one very quickly (on average).
Here is a code example of how to use HashMap using Person.name as the key, this assumes that there is never a person with the same name.
public class Main
{
private HashMap<String, Person> people = new HashMap<String, Person>();
public void addPerson(Person person)
{
people.put(person.getName(), person);
}
public Person getPerson(String name)
{
// get returns null when not found
return people.get(name);
}
}