I'm trying to understand how to use the Java 8 Streams API.
For example, I have these two classes:
public class User {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
public class UserWithAge {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
private int age;
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
I have a List<User> of ten users, and I want to convert this to a List<UserWithAge> of ten users with the same names and with a constant age (say, 27). How can I do that using the Java 8 Streams API (without loops, and without modifying the above classes)?
You could use the map() feature of the stream to convert each User instance in your list to a UserWithAge instance.
List<User> userList = ... // your list
List<UserWithAge> usersWithAgeList = userList.stream()
.map(user -> {
// create UserWithAge instance and copy user name
UserWithAge userWithAge = new UserWithAge();
userWithAge.setName(user.getName());
userWithAge.setAge(27);
return userWithAge;
})
.collect(Collectors.toList()); // return the UserWithAge's as a list
While you could do this, You should not do like this.
List<UserWithAge> userWithAgeList = new ArrayList<UserWithAge>();
userList.stream().forEach(user -> {
UserWithAge userWithAge = new UserWithAge();
userWithAge.setName(user.getName());
userWithAge.setAge(27);
userWithAgeList.add(userWithAge);
});
public class ListIteratorExp {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
Person p1 = new Person();
p1.setName("foo");
Person p2 = new Person();
p2.setName("bee");
list.add(p1);
list.add(p2);
list.stream().forEach(p -> {
String name = p.getName();
System.out.println(name);
});
}
}
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
output:-
vishal
thakur
Related
I am trying to write a program which stores information about a person in a linked list. I made a simple person class to store the name, age and addresses in the list. I would also like to store multiple addresses for EACH person, and a fact about the place in another linked list, inside the person class.
So for example, "Tara" can have a home address of "10 Central Ave" and a work address of "5 Willow street" etc. The problem is, I don't know how to have a linked list inside another.
My goal is to check whether the person's name is already on the list, and if so, add another address for them. (So that there is no repeats). I am a beginner and can really use some help.
public class Person {
private String name;
private int age;
public LinkedList <String> adresses;
public Person() {
name = "default";
age = 0;
adresses = new LinkedList<>();
}
public Person(String n, int a) {
name = n;
age = a;
}
public LinkedList<Adress> getAdresses() {
return adresses;
}
public void setAdresses(LinkedList<Adress> adresses) {
this.adresses = adresses;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return name+" "+age+" "+adresses;
}
}
public class Adress {
public String adress;
public String fact;
public Adress(String a, String f) {
adress = a;
fact = f;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
public String getFact() {
return fact;
}
public void setFact(String fact) {
this.fact = fact;
}
}
public class Test {
public static void main(String[] args) {
Person Tara = new Person("Tara",35);
Person Judah = new Person("Judah",28);
Person Mark = new Person("Mark",45);
Person Seth = new Person("Seth",23);
LinkedList<Object> tester = new LinkedList<>();
tester.add(Tara);
tester.add(Judah);
tester.addLast(Mark);
tester.addLast(Seth);
System.out.println(tester);
}
}
How is about to use the next classic data structure for your project?
public class Person {
private String name
private int age;
public List<Address> addresses;
//...
}
"This question is for a free online course I am taking. Below is the instructors direction and below that is my answer. I must be solving the problem wrong because the automatic grading system marks it incorrect even though I got the correct output. I believe the instructor wanted me to fill an array in the Main class with objects from the person class and I am unsure how to do that. Please help if you know how to do that or if you have a better idea of what the instructor wanted."
Instructors direction
In your main method, make an array of type Person Fill it with Person objects of the following people and then print the names of each from that array. Each person should be on their own line formatted as shown below.
Fred, 24
Sally, 26
Billy, 15
main.java
class Main {
public static Person[] people;
public static void main(String[] args) {
Person personObject = new Person();
personObject.Person();
}
}
Person.java
public class Person{
public static String[] Person(){
String[] people = {"Fred, 24", "Sally, 26", "Billy, 15"};
for(int i=0; i< people.length; i++){
System.out.println(people[i]);
}
return people;
}
}
It says you need objects and array. So i guess you wanted something like this.
Person.java
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#Override
public String toString() {
return "Person{" + "name=" + name + ", age=" + age + '}';
}
}
By declaring Person p1 = new Person("Sally",26); you are creating object of class Person. You can use that as many times as you want and create different objects. We use override method toString to print informations about Person. We could also use p1.getName() and p1.getAge()
Main
public static void main(String[] args) {
Person p1 = new Person("Fred", 24);
Person p2 = new Person("Sally", 26);
Person p3 = new Person("Billy", 55);
Person[] people = {p1,p2,p3};
for(Person p : people){
System.out.println(p.toString());
}
}
I think what your professor wants is something like this :)
public class Runner {
public static void main(String args[])throws Exception{
Persons person1 = new Persons();
Persons person2 = new Persons();
Persons person3 = new Persons();
person1.setName("Fred");
person1.setAge("24");
person2.setName("Sally");
person2.setAge("26");
person3.setName("Billy");
person3.setAge("15");
String[] list = {person1.toString(), person2.toString(), person3.toString()};
for (int i = 0; i < list.length; i++) {
System.out.println(list[i]);
}
}
}
public class Persons {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
#Override
public String toString() {
return name + ", " + age;
}
}
I have an arrayList of EmployeeDetails object and another arrayList of EmployeeSalary object.I want to create a new ArrayList that has both the attributes of EmployeeDetails and EmployeeSalary.My EmployeeDetails class has attributes "id" and "name".My EmployeeSalary class has attributes "id" and "salary".I want an arraylist with attributes "id","name" and "salary".
EmployeeDetails Class
public class EmployeeDetails {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
EmployeeSalary class
public class EmployeeSalary {
private String id;
private String sal;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSal() {
return sal;
}
public void setSal(String sal) {
this.sal = sal;
}
}
First, set up a map to access the salaries from the IDs:
Map<String, String> salaryMappings = new HashMap();
for(EmployeeSalary salary : salaries) {
salaryMappings.put(salary.getId(), salary.getSal());
}
(where your salary ArrayList is named salaries).
Next, you need a class to store the information (note I'm not writing the accessors for sake of keeping the post short, though you should add them):
class EmployeeInformation {
String id;
String name;
String sal;
public EmployeeInformation(String id, String name, String sal) {
this.id = id;
this.name = name;
this.sal = sal;
}
}
Finally, copy the values into a new ArrayList:
List<EmployeeInformation> infos = new ArrayList<EmployeeInformation>();
for(EmployeeDetails detail : details) {
infos.add(new EmployeeInformation( details.getId(), details.getName(), salaryMappings.get(details.getId()) ));
}
EmployeeSalary should extend Employeedetails
public class EmployeeSalary extends EmployeeDetails{
private String sal;
...
After that, in order to merge two lists arraylist1.addAll(arraylist2) should be invoked.
No need to use HashMap or Map. Just use java 8 lambda :)
Create EmployeeInformation.java class.
public class EmployeeInformation {
String id;
String name;
String sal;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSal() {
return sal;
}
public void setSal(String sal) {
this.sal = sal;
}
public EmployeeInformation(String id, String name, String sal) {
this.id = id;
this.name = name;
this.sal = sal;
}
}
Find the full solution.
List<EmployeeDetails> employeeDetailsList = new ArrayList<>();
EmployeeDetails employeeDetails1 = new EmployeeDetails();
employeeDetails1.setId("A");
employeeDetails1.setName("EMP1");
employeeDetailsList.add(employeeDetails1);
EmployeeDetails employeeDetails2 = new EmployeeDetails();
employeeDetails2.setId("B");
employeeDetails2.setName("EMP2");
employeeDetailsList.add(employeeDetails2);
List<EmployeeSalary> employeeSalariesList = new ArrayList<>();
EmployeeSalary employeeSalary1 = new EmployeeSalary();
employeeSalary1.setId("A");
employeeSalary1.setSal("SAL1");
employeeSalariesList.add(employeeSalary1);
EmployeeSalary employeeSalary2 = new EmployeeSalary();
employeeSalary2.setId("B");
employeeSalary2.setSal("SAL2");
employeeSalariesList.add(employeeSalary2);
List<EmployeeInformation> employeeInformationList = new ArrayList<>();
employeeDetailsList.forEach(employeeDetails -> {
String _id = employeeDetails.getId();
String _name = employeeDetails.getName();
employeeSalariesList.stream().filter(employeeSalary -> employeeSalary.getId().equalsIgnoreCase(_id)).forEach(employeeSalary -> {
EmployeeInformation employeeInformation = new EmployeeInformation(_id, _name, employeeSalary.getSal());
employeeInformationList.add(employeeInformation);
});
});
for (EmployeeInformation employeeInformation : employeeInformationList) {
System.out.println(employeeInformation.getId() + "-" + employeeInformation.getName() + "-" + employeeInformation.getSal());
}
Output ->
A-EMP1-SAL1
B-EMP2-SAL2
You can convert the two collections to maps of id->value and then do a secondary lookup.
The following constructs a collection of Map<String, String> with the keys required in your result:
List<EmployeeDetails> details = ...;
List<EmployeeSalary> salaries = ...;
Map<String, EmployeeDetails> detailsMap = details.stream()
.collect(Collectors.groupingBy(EmployeeDetails::getId,
Collectors.reducing(null, (e1, e2) -> e1)));
Map<String, EmployeeSalary> salariesMap = salaries.stream()
.collect(Collectors.groupingBy(EmployeeSalary::getId,
Collectors.reducing(null, (e1, e2) -> e1)));
List<Map<String, String>> summaries = detailsMap.entrySet().stream()
.map(entry -> {
Map<String, String> m = new HashMap<>();
m.put("id", entry.getKey());
m.put("name", entry.getValue().getName());
m.put("salary", salariesMap.get(entry.getKey()).getSal());
return m;
}).collect(Collectors.toList());
It's likely that you'll choose to build a separate class for the summary, having the id, name, and salary fields, instead of using a Map. But this is an idea of how to go about it.
I think, the best solution is to create another class (e.g. EmployeeData) and collect all required data there. In case you do not want (or cannot) modify definitions of EmployeeDetails and EmployeeSalry.
class EmployeeData {
private final String id;
private String name;
private String sal;
public EmployeeData(String id) {
this.id = id;
}
}
private static List<EmployeeData> merge(List<EmployeeDetails> details, List<EmployeeSalary> salaries) {
Map<String, EmployeeData> data = new HashMap<>();
String id;
for (EmployeeDetails detail : details) {
id = detail.getId();
if (!data.containsKey(id))
data.put(id, new EmployeeData(id));
data.get(id).setName(detail.getName());
}
for (EmployeeSalary salary : salaries) {
id = salary.getId();
if (!data.containsKey(id))
data.put(id, new EmployeeData(id));
data.get(id).setSal(salary.getSal());
}
return new ArrayList<>(data.values());
}
I am having some trouble with this. I want to add the member variables to a map.
Here is my code:
Sprinter.java
public class Sprinter {
private int age;
private String name;
private String address;
public Sprinter() {
}
public Sprinter(int age, String name, String address) {
this.age = age;
this.name = name;
this.address = address;
}
public void setAge(int age) {
return this.age = age;
}
public int getAge() {
return this.age;
}
public void setName(String name) {
return this.age = age;
}
public String getName() {
return this.name;
}
public void setAddress(String address) {
return this.address = address;
}
public String getAddress() {
return this.address;
}
Worker.java
Sprinter _s = new Sprinter();
_s.setAge(16);
_s.setName("Chris");
_s.setAddress("123 Street");
Map.java
public class Maper {
private Sprinter _sp = new Sprinter();
private static Map<String, Sprinter> map = new HashMap<String, Sprinter>();
public void printMap() {
map.put(_sp.getName(), _sp);
System.out.println(map);
I want the String in the map to be the key, and the values to be the age, address, and name fields from the Sprinter class. In my Worker.java class I use:
Maper _m = new Maper();
_m.printMap();
And my output is: {"Chris", "Chris"};
However, I want all of the variables to be added. Any advice?
A map relates a single key with a single value - it explicitly can't relate a single key ("Chris") with three different values (16, "Chris", "123 Street"). You have two obvious choices:
Use three different keys (e.g. "Chris_age" -> 16, "Chris_name" -> "Chris", "Chris_address" -> "123 Street"). This option is further complicated because the values are of different types (int vs String) so you'd need to declare your map as Map<String, Object> which is generally not great. The insert code would look something like:
map.put(_sp.getName() + "_name", _sp.getName());
map.put(_sp.getName() + "_age", _sp.getAge());
map.put(_sp.getName() + "_address", _sp.getAddress());
The better option is to use a container object to hold the three values, and store that in the map. That's what the code you already have does. In that case, if you want the age you need to do something like:
map.get("Chris").getAge();
This question already has answers here:
How can I sort a List alphabetically?
(15 answers)
Closed 9 years ago.
I have an array of objects and each objects has a given name and a surname.
These names are written to the object using methods getGivenName and getSurname.
I need to sort the elements in the array in alphabetical order by surname.
how can I do this?
Your comparator
class SampleComparator implements Comparator<YourObject> {
#Override
public int compare(YourObject o1, YourObject o2) {
return o1.getSurname().compareTo(o2.getSurname());
}
}
Your Sorting
Collections.sort(YourList, new SampleComparator())
if you need ignore case then use like
return o1.getSurname().compareToIgnoreCase(o2.getSurname());
Use List rather than using Array. Your class needs to implements Comparable interface.
Please see the code,
By Implementing Comparable interface
public class Person implements Comparable<Person>{
private String givenName;
private String surname;
public static void main(String[] args) {
Person person1 = new Person("a","b");
Person person2 = new Person("c","d");
Person person3 = new Person("e","f");
List<Person> personList = new ArrayList<Person>();
personList.add(person1);
personList.add(person2);
personList.add(person3);
Collections.sort(personList);
System.out.println(personList);
}
#Override
public String toString() {
return "WorkSheet [givenName=" + givenName + ", surname=" + surname
+ "]";
}
public Person() {
// TODO Auto-generated constructor stub
}
public Person(String givenName , String surname) {
this.givenName = givenName;
this.surname = surname;
}
public String getGivenName() {
return givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
#Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
return o.getSurname().compareTo(this.getSurname());
}
}
By Implementing Comaparator Interface
public class Person implements Comparator<Person>{
private String givenName;
private String surname;
public static void main(String[] args) {
Person person1 = new Person("a","b");
Person person2 = new Person("c","d");
Person person3 = new Person("e","f");
List<Person> personList = new ArrayList<Person>();
personList.add(person1);
personList.add(person2);
personList.add(person3);
Collections.sort(personList , new Person());
System.out.println(personList);
}
#Override
public String toString() {
return "WorkSheet [givenName=" + givenName + ", surname=" + surname
+ "]";
}
public Person() {
// TODO Auto-generated constructor stub
}
public Person(String givenName , String surname) {
this.givenName = givenName;
this.surname = surname;
}
public String getGivenName() {
return givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
#Override
public int compare(Person o1, Person o2) {
// TODO Auto-generated method stub
return o2.getSurname().compareTo(o1.getSurname());
}
}
When sorting natural language texts, it's recommended to use a Collator and CollationKeys. The String.compareTo method mentioned by other answers will compare Strings based on the Unicode value of each character in the strings, which might not be what you want/ expect, depending on your input Strings and locale.
Note that I wrote some utility methods to help sorting natural language texts.
E.g. you coud try something like:
public class PersonLocalizer implements Localizer<Person> {
#Override
public String getDisplayString(Person person, Locale inLocale) {
return person.getSurname();
}
}
[...]
Localizables.sort(new PersonLocalizer (), persons);
Maven:
<dependency>
<groupId>org.softsmithy.lib</groupId>
<artifactId>softsmithy-lib-core</artifactId>
<version>0.3</version>
</dependency>