Cannot add element to ObservableList (UnsupportedOperationException) in JavaFX [duplicate] - java

This question already has answers here:
Why do I get an UnsupportedOperationException when trying to remove an element from a List?
(17 answers)
Closed 6 years ago.
Initial Starting Point
I have an existing List of 1000 Person objects which I would like to insert an Extractor to listen for property changes within any Person objects (this ObservableList will be later attached to a TableView).
So my code would be like:
ObservableList<Person> observablePersons = FXCollections.observableList(personlist,
personextractor);
Error Message
But when I try to add a new person objects to this ObservableList observablePersons, I run into this error:
run:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at com.sun.javafx.collections.ObservableListWrapper.doAdd(ObservableListWrapper.java:101)
at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:151)
at java.util.AbstractList.add(AbstractList.java:108)
at test.listchangelistener.listChangeDemo.main(listChangeDemo.java:72)
Java Result: 1
Could you please tell me why would I come across this error message? My java version is jdk1.8.0_91 (32-Bit)
Person Class
package test.listchangelistener;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
class Person {
private final IntegerProperty age = new SimpleIntegerProperty();
private final StringProperty name = new SimpleStringProperty();
public Person(String name, Integer age) {
setName(name);
setAge(age);
}
public int getAge() {
return age.get();
}
public final void setAge(int value) {
age.set(value);
}
public IntegerProperty ageProperty() {
return age;
}
public String getName() {
return name.get();
}
public final void setName(String value) {
name.set(value);
}
public StringProperty nameProperty() {
return name;
}
#Override
public String toString() {
return "Person{" + "age=" + age.get() + ", name=" + name.get() + '}';
}
}
Test Code
package test.listchangelistener;
import java.util.Arrays;
import java.util.List;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.util.Callback;
public class listChangeDemo {
public static void main(String[] args) {
Person p1 = new Person("Ted", 26);
Person p2 = new Person("Anne", 19);
// just a simple list
List<Person> persons = Arrays.asList(p1, p2);
// extractor to observe change of person properties
Callback<Person, Observable[]> extractor = (Person p) -> {
return new Observable[]{
p.ageProperty(),
p.nameProperty()
};
};
// make list observable and attach extractor
ObservableList<Person> observablePersons = FXCollections.observableList(persons, extractor);
// create listchangeListener for observableList
ListChangeListener listener = (ListChangeListener) (ListChangeListener.Change c) -> {
while (c.next()) {
if (c.wasAdded()) {
System.out.println("these were added: ");
List addedSubList = c.getAddedSubList();
addedSubList.forEach((Object t) -> {
System.out.println("added Person: " + t);
});
} else if (c.wasRemoved()) {
System.out.println("these were removed");
List removedSubList = c.getRemoved();
removedSubList.forEach((Object t) -> {
System.out.println("removed Person: " + t);
});
} else if (c.wasUpdated()) {
System.out.println("these were updated");
System.out.println("Updated elements are: "
+ c.getList().subList(c.getFrom(), c.getTo()));
}
}
};
// attach listchangeListener to observableList
observablePersons.addListener(listener);
// testing changes
observablePersons.add(new Person("Siegfried", 10));
}
}

The problem is coming from the creation of your backing List:
List<Person> persons = Arrays.asList(p1, p2);
If you take a look on the javadoc of Arrays.asList:
Returns a fixed-size list backed by the specified array.
On a closer look you got an UnsupportedOperationException because List.add() is an optional operation:
Throws:
UnsupportedOperationException - if the add operation is not supported by this list.
You can update the creation of the backing list as:
List<Person> persons = new ArrayList<Person>(Arrays.asList(p1, p2));
The difference is that the returned ArrayList is an exact, independent copy of the passed one, therefore the restriction described above is not valid anymore in this case.
You can also take a look on this question which explaines this topic in depths:
Difference between Arrays.asList(array) vs new ArrayList<Integer>(Arrays.asList(ia)) in java

Related

To return actor older than a certain age limit using Java Stream filter function

I want to return actor older than a certain age limit using Java Stream filter function, but my code returned an error message
Line 63: error: cannot find symbol [in Actor.java]
.filter(actor -> actor.getAge > ageLimit)
symbol: variable getAge
location: variable actor of type Actor
My code is as below:
import java.util.*;
import java.io.*;
import java.nio.*;
import java.math.*;
import java.time.chrono.IsoChronology;
import java.time.LocalDate;
import java.util.stream.Collectors;
class Actor {
String name;
LocalDate birthday;
Actor(String nameArg, LocalDate birthdayArg) {
name = nameArg;
birthday = birthdayArg;
}
public int getAge() {
return birthday
.until(IsoChronology.INSTANCE.dateNow())
.getYears();
}
public String getName() {
return name;
}
public static List<Actor> createCast() {
List<Actor> cast = new ArrayList();
cast.add(
new Actor(
"Fred",
IsoChronology.INSTANCE.date(1980, 6, 20)));
cast.add(
new Actor(
"0mar",
IsoChronology.INSTANCE.date(1990, 12, 10)));
return cast;
}
public void printActor() {
System.out.println(name + ", " + this.getAge()); }
}
class cast {
interface CheckPerson {
boolean test (Actor p);
}
public static void printActors (List<Actor> cast) {
for (Actor p: cast) {
p.printActor();
}
}
public static List<Actor> getActorsolderThan(List<Actor> cast, int ageLimit) {
List<Actor> result = cast.stream() // convert list to stream
.filter(actor -> actor.getAge > ageLimit) //TODO
.collect(Collectors. toList());
return result;
}
}
The test code is as below:
//Test Code:
List<Actor> cast = Actor.createCast();
List<Actor> castolderThan = Cast.getActorsolderThan(cast, 30);
Cast.printActors(cast);
May I ask how exactly should I use filter function to return actor older than a certain age limit by editing the code on the filter line in the getActorsolderThan method?
I think this line should be like this
List<Actor> result = cast.stream() // convert list to stream
.filter(actor -> actor.getAge() > 100) //TODO
.collect(Collectors. toList());
getAge is a function not a class variable

How to create custom Comparator to rank search results?

This is a followup to a prior question I posted here.
In the MCVE below, I have a TableView displaying a list of Person objects. Above the list, I have a single TextField which I use to filter the listed items in the TableView.
The Person class contains 4 fields, but I have my search field only checking for matches in 3 of them: userId, lastName, and emailAddress.
The filtering function works as expected.
However, I now need to rank the results based on which fields were matched and the user Type.
MCVE CODE
Person.java:
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public final class Person {
private StringProperty userType = new SimpleStringProperty();
private IntegerProperty userId = new SimpleIntegerProperty();
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
private StringProperty emailAddress = new SimpleStringProperty();
public Person(String type, int id, String firstName, String lastName, String emailAddress) {
this.userType.set(type);
this.userId.set(id);
this.firstName.set(firstName);
this.lastName.set(lastName);
this.emailAddress.set(emailAddress);
}
public String getUserType() {
return userType.get();
}
public void setUserType(String userType) {
this.userType.set(userType);
}
public StringProperty userTypeProperty() {
return userType;
}
public int getUserId() {
return userId.get();
}
public void setUserId(int userId) {
this.userId.set(userId);
}
public IntegerProperty userIdProperty() {
return userId;
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public StringProperty lastNameProperty() {
return lastName;
}
public String getEmailAddress() {
return emailAddress.get();
}
public void setEmailAddress(String emailAddress) {
this.emailAddress.set(emailAddress);
}
public StringProperty emailAddressProperty() {
return emailAddress;
}
}
Main.java:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.Comparator;
public class Main extends Application {
TableView<Person> tableView;
private TextField txtSearch;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
// Create the TableView of data
tableView = new TableView<>();
TableColumn<Person, Integer> colId = new TableColumn<>("ID");
TableColumn<Person, String> colFirstName = new TableColumn<>("First Name");
TableColumn<Person, String> colLastName = new TableColumn<>("Last Name");
TableColumn<Person, String> colEmailAddress = new TableColumn<>("Email Address");
// Set the ValueFactories
colId.setCellValueFactory(new PropertyValueFactory<>("userId"));
colFirstName.setCellValueFactory(new PropertyValueFactory<>("firstName"));
colLastName.setCellValueFactory(new PropertyValueFactory<>("lastName"));
colEmailAddress.setCellValueFactory(new PropertyValueFactory<>("emailAddress"));
// Add columns to the TableView
tableView.getColumns().addAll(colId, colFirstName, colLastName, colEmailAddress);
// Create the filter/search TextField
txtSearch = new TextField();
txtSearch.setPromptText("Search ...");
addSearchFilter(getPersons());
// Add the controls to the layout
root.getChildren().addAll(txtSearch, tableView);
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
private void addSearchFilter(ObservableList<Person> list) {
FilteredList<Person> filteredList = new FilteredList<Person>(list);
txtSearch.textProperty().addListener(((observable, oldValue, newValue) ->
filteredList.setPredicate(person -> {
// Clear any currently-selected item from the TableView
tableView.getSelectionModel().clearSelection();
// If search field is empty, show everything
if (newValue == null || newValue.trim().isEmpty()) {
return true;
}
// Grab the trimmed search string
String query = newValue.trim().toLowerCase();
// Convert the query to an array of individual search terms
String[] keywords = query.split("[\\s]+");
// Create a single string containing all the data we will match against
// BONUS QUESTION: Is there a better way to do this?
String matchString =
String.valueOf(person.getUserId())
+ person.getLastName().toLowerCase()
+ person.getEmailAddress().toLowerCase();
// Check if ALL the keywords exist in the matchString; if any are absent, return false;
for (String keyword : keywords) {
if (!matchString.contains(keyword)) return false;
}
// All entered keywords exist in this Person's searchable fields
return true;
})));
SortedList<Person> sortedList = new SortedList<>(filteredList);
// Create the Comparator to allow ranking of search results
Comparator<Person> comparator = new Comparator<Person>() {
#Override
public int compare(Person person, Person t1) {
return 0;
}
};
// Set the comparator and bind list to the TableView
sortedList.setComparator(comparator);
tableView.setItems(sortedList);
}
private ObservableList<Person> getPersons() {
ObservableList<Person> personList = FXCollections.observableArrayList();
personList.add(new Person("DECEASED", 123, "Chrissie", "Watkins", "fishfood#email.com"));
personList.add(new Person("VET", 342, "Matt", "Hooper", "m.hooper#noaa.gov"));
personList.add(new Person("VET", 526, "Martin", "Brody", "chiefofpolice#amity.gov"));
personList.add(new Person("NEW", 817, "Larry", "Vaughn", "lvaughn#amity.gov"));
return personList;
}
}
You'll see I have an empty Comparator in my Main class. This is what I need help with. I have created comparators in the past that are able to sort based on one field (from my previous question):
Comparator<DataItem> byName = new Comparator<DataItem>() {
#Override
public int compare(DataItem o1, DataItem o2) {
String searchKey = txtSearch.getText().toLowerCase();
int item1Score = findScore(o1.getName().toLowerCase(), searchKey);
int item2Score = findScore(o2.getName().toLowerCase(), searchKey);
if (item1Score > item2Score) {
return -1;
}
if (item2Score > item1Score) {
return 1;
}
return 0;
}
private int findScore(String item1Name, String searchKey) {
int sum = 0;
if (item1Name.startsWith(searchKey)) {
sum += 2;
}
if (item1Name.contains(searchKey)) {
sum += 1;
}
return sum;
}
};
I am not sure how to adapt this for multiple fields, though. Specifically, I want to be able to choose which fields should be ranked "higher."
For this example, what I want to accomplish is to sort the list in this order:
userId starts with a keyword
lastName starts with a keyword
emailAddress starts with a keyword
lastName contains a keyword
emailAddress contains a keyword
Within matches any userType = "VET" should be listed first
I am not looking for Google-level algorithms, but just some way to prioritize matches. I am not very familiar with the Comparator class and have a hard time understanding the JavaDocs for it, as it applies to my needs.
There are several posts on StackOverflow that deal with sorting by multiple fields, but all those I've found are comparing Person to Person. Here, I need to compare Person fields to the txtSearch.getText() value.
How would I go about refactoring this Comparator to set up custom sorting of this nature?
Your scoring concept is close, you just need to come up with factors and follow the rules.
So, here's a simple example:
public int score(Item item, String query) {
int score = 0;
if (item.userId().startsWith(query) {
score += 2000;
}
if (item.lastName().startsWith(query) {
score += 200;
} else if (item.lastName().contains(query) {
score += 100;
}
if (item.email().startsWith(query) {
score += 20;
} else if (item.email().contains(query) {
score += 10;
}
if (item.userType().equals("VET")) {
score += 5;
}
return score;
}
So as you can see, I took each of your criteria and turned them in to different digits within the score, and for the distinction within each criteria, I had different values (10 vs 20, for example). Finally I tacked on 5 for the "VET" type.
The assumption is that the scoring rules are not exclusive (i.e. that each rule refines the scoring, rather than stops it), and the the VET types were tie breakers within each criteria, vs to the top of the list. If VET needs to go to the top of the list (i.e. all VETs will be show before all non-VET), you can change the 5 to 10000, giving it it's own order of magnitude.
Now, using decimal numbers is just easy, but you'll run out of magnitudes after 9 (you'll overflow the int) -- you could also use other bases (base 3 in this example), giving you access to more "bits" in the integer. You could use a long, Or you could use a BigDecimal value and have as many criteria as you like.
But the basics are the same.
Once you have the score, just compare the scores of the two values in your comparator.
You can sort for multiple fields by chaining comparators together. If the first comparator declares two objects to be equal you delegate to the next comparator and continue like this until all comparators have been queried or any of them have returned a value other than 0.
Here is an example:
static class Person {
String name;
int age;
int id;
}
Comparator<Person> c3 = (p1, p2) -> {
return Integer.compare(p1.id, p2.id);
};
Comparator<Person> c2 = (p1, p2) -> {
if (p1.name.compareTo(p2.name) == 0) {
return c3.compare(p1, p2);
}
return p1.name.compareTo(p2.name);
};
Comparator<Person> c1 = (p1, p2) -> {
if (Integer.compare(p1.age, p2.age) == 0) {
return c2.compare(p1, p2);
}
return Integer.compare(p1.age, p2.age);
};
The comparators are queried in the sequence of c1 then c2 then c3.
Of course this is an overly simplified example. In production code you should preferably use a cleaner and more OOP oriented solution.

Remove duplicate from a java collection

public class Employee implements Comparable<Employee> {
private int id;
private String name;
private String salary;
private String recordStatus;
private int key;
public Employee(int id, String name, String salary, int key) {
super();
this.id = id;
this.name = name;
this.salary = salary;
this.key = key;
}
}
Now I have a list of type Employee.
List<Employee> list = new ArrayList<Employee>();
list.add(new Employee(123, "zMadhu", "1000$",1));
list.add(new Employee(332, "bSudhan", "2000$",2));
list.add(new Employee(54, "cKongarass", "3000$",3));
list.add(new Employee(54, "xKongarass", "3000$",4));
list.add(new Employee(54, "aKongarass", "3000$",5));
Now I want to remove data from this list and have only unique IDS. I.E. I am expecting 54,123,332 in another list of type Employee.
Want to see how I can do it. Much appreciate your help here.
First override equals(..) and hashCode() where you use just the id :
...
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Employee)) return false;
Employee employee = (Employee) o;
return id == employee.id;
}
#Override
public int hashCode() {
return id;
}
...
Second Just create a Set<Employee> which will not accept duplicates Objects like so :
Set<Employee> result = new HashSet<>(list);// [54, 123, 332]
Take a look at a simple Ideone demo
First of all, this code won't compile because you don't have the comparable interface implemented. So, I just took that out for now assuming you left it out for brevity :).
Assuming you had that... the most sensible thing would be to use a map in the first place.
Assuming you want to start with this list though, you can convert this to a map and log/remove duplicates with a stream:
Map<Integer, Employee> employees = list.stream()
.collect(Collectors.toMap(k -> k.id, v -> v, (a, b) -> {
System.out.println("Duplicate found! " + a.id + " taking first one.");
return a;
}));
System.out.println(employees);
Results:
Duplicate found! 54 taking first one.
Duplicate found! 54 taking first one.
{54=Employee{id=54, name='cKongarass', salary='3000$',
recordStatus='null', key=3}, 123=Employee{id=123, name='zMadhu',
salary='1000$', recordStatus='null', key=1}, 332=Employee{id=332,
name='bSudhan', salary='2000$', recordStatus='null', key=2}}
Note for employees to print properly you need to add a toString() method to the class.
Person Class toString() Function:
#Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", salary='" + salary + '\'' +
", recordStatus='" + recordStatus + '\'' +
", key=" + key +
'}';
}
If you override the equals method accordingly you can do it this way in java 8+:
import java.util.stream.Collectors;
list.stream().distinct().collect(Collectors.toList())
It's also achievable without overriding the equals method, but more verbose though:
Set<Employee> uniqueSet = new TreeSet<>((e1, e2) -> e1.getId() == e2.getId() ? 0 : 1);
set.addAll(list);
List<Employee> result = new ArrayList<>(uniqueSet);
The lambda passed to the TreeSet constructor gets expanded to an implementation of Comparator<Employee>. Similar to the solution provided by #bsb but using java 8 features.
The easiest way to remove duplicate is by passing the List to a Set and Use Comparator to remove duplicate elements.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class RemoveDuplicate {
public static void main(String[] args) {
List<Employee> list = new ArrayList<Employee>();
list.add(new Employee(123, "zMadhu", "1000$",1));
list.add(new Employee(332, "bSudhan", "2000$",2));
list.add(new Employee(54, "cKongarass", "3000$",3));
list.add(new Employee(54, "xKongarass", "3000$",4));
list.add(new Employee(54, "aKongarass", "3000$",5));
//Printing original list
for (Employee emp : list) {
System.out.println(emp.getId());
}
Set<Employee> set = new TreeSet<Employee>(new Comparator<Employee>() {
#Override
public int compare(Employee e1, Employee e2) {
return e1.getId() == e2.getId() ? 0 : 1;
}
});
set.addAll(list);
final ArrayList<Employee> newList = new ArrayList<Employee>(set);
System.out.println("\n***** After removing duplicates *******\n");
for (Employee emp : newList) {
System.out.println(emp.getId());
}
}
}

Sorting a list with stream.sorted() in Java

I'm interested in sorting a list from a stream. This is the code I'm using:
list.stream()
.sorted((o1, o2)->o1.getItem().getValue().compareTo(o2.getItem().getValue()))
.collect(Collectors.toList());
Am I missing something? The list is not sorted afterward.
It should sort the lists according to the item with the lowest value.
for (int i = 0; i < list.size(); i++)
{
System.out.println("list " + (i+1));
print(list, i);
}
And the print method:
public static void print(List<List> list, int i)
{
System.out.println(list.get(i).getItem().getValue());
}
This is not like Collections.sort() where the parameter reference gets sorted. In this case you just get a sorted stream that you need to collect and assign to another variable eventually:
List result = list.stream().sorted((o1, o2)->o1.getItem().getValue().
compareTo(o2.getItem().getValue())).
collect(Collectors.toList());
You've just missed to assign the result
Use list.sort instead:
list.sort((o1, o2) -> o1.getItem().getValue().compareTo(o2.getItem().getValue()));
and make it more succinct using Comparator.comparing:
list.sort(Comparator.comparing(o -> o.getItem().getValue()));
After either of these, list itself will be sorted.
Your issue is that
list.stream.sorted returns the sorted data, it doesn't sort in place as you're expecting.
Java 8 provides different utility api methods to help us sort the streams better.
If your list is a list of Integers(or Double, Long, String etc.,) then you can simply sort the list with default comparators provided by java.
List<Integer> integerList = Arrays.asList(1, 4, 3, 4, 5);
Creating comparator on fly:
integerList.stream().sorted((i1, i2) -> i1.compareTo(i2)).forEach(System.out::println);
With default comparator provided by java 8 when no argument passed to sorted():
integerList.stream().sorted().forEach(System.out::println); //Natural order
If you want to sort the same list in reverse order:
integerList.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println); // Reverse Order
If your list is a list of user defined objects, then:
List<Person> personList = Arrays.asList(new Person(1000, "First", 25, 30000),
new Person(2000, "Second", 30, 45000),
new Person(3000, "Third", 35, 25000));
Creating comparator on fly:
personList.stream().sorted((p1, p2) -> ((Long)p1.getPersonId()).compareTo(p2.getPersonId()))
.forEach(person -> System.out.println(person.getName()));
Using Comparator.comparingLong() method(We have comparingDouble(), comparingInt() methods too):
personList.stream().sorted(Comparator.comparingLong(Person::getPersonId)).forEach(person -> System.out.println(person.getName()));
Using Comparator.comparing() method(Generic method which compares based on the getter method provided):
personList.stream().sorted(Comparator.comparing(Person::getPersonId)).forEach(person -> System.out.println(person.getName()));
We can do chaining too using thenComparing() method:
personList.stream().sorted(Comparator.comparing(Person::getPersonId).thenComparing(Person::getAge)).forEach(person -> System.out.println(person.getName())); //Sorting by person id and then by age.
Person class
public class Person {
private long personId;
private String name;
private int age;
private double salary;
public long getPersonId() {
return personId;
}
public void setPersonId(long personId) {
this.personId = personId;
}
public Person(long personId, String name, int age, double salary) {
this.personId = personId;
this.name = name;
this.age = age;
this.salary = salary;
}
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 double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
It seems to be working fine:
List<BigDecimal> list = Arrays.asList(new BigDecimal("24.455"), new BigDecimal("23.455"), new BigDecimal("28.455"), new BigDecimal("20.455"));
System.out.println("Unsorted list: " + list);
final List<BigDecimal> sortedList = list.stream().sorted((o1, o2) -> o1.compareTo(o2)).collect(Collectors.toList());
System.out.println("Sorted list: " + sortedList);
Example Input/Output
Unsorted list: [24.455, 23.455, 28.455, 20.455]
Sorted list: [20.455, 23.455, 24.455, 28.455]
Are you sure you are not verifying list instead of sortedList [in above example] i.e. you are storing the result of stream() in a new List object and verifying that object?
sorting Integer using streamAPI
arr.stream()
.sorted((item1,item2)-> Integer.compare(item1.price, item2.price))
.forEach(item-> item.show());
//asc
System.out.println("--------------------");
//desc
arr.stream()
.sorted((item1,item2)-> item1.price<item2.price?1:-1)
.forEach(item->item.show());
This is a simple example :
List<String> citiesName = Arrays.asList( "Delhi","Mumbai","Chennai","Banglore","Kolkata");
System.out.println("Cities : "+citiesName);
List<String> sortedByName = citiesName.stream()
.sorted((s1,s2)->s2.compareTo(s1))
.collect(Collectors.toList());
System.out.println("Sorted by Name : "+ sortedByName);
It may be possible that your IDE is not getting the jdk 1.8 or upper version to compile the code.
Set the Java version 1.8 for Your_Project > properties > Project Facets > Java version 1.8
This might help for people ending up here searching how to sort list alphabetically.
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class SortService {
public static void main(String[] args) {
List<TestData> test = new ArrayList<>();
test.add(prepareTestData("Asmin",1));
test.add(prepareTestData("saurav",4));
test.add(prepareTestData("asmin",2));
test.add(prepareTestData("Saurav",3));
test.forEach(data-> System.out.println(data));
/** Output
* TestData(name=Asmin, id=1)
* TestData(name=saurav, id=4)
* TestData(name=asmin, id=2)
* TestData(name=Saurav, id=3)
*/
test.sort(Comparator.comparing(TestData::getName,String::compareToIgnoreCase));
test.forEach(data-> System.out.println(data));
/**Sorted Output
* TestData(name=Asmin, id=1)
* TestData(name=asmin, id=2)
* TestData(name=saurav, id=4)
* TestData(name=Saurav, id=3)
*/
}
private static TestData prepareTestData(String name, int id){
TestData testData= new TestData();
testData.setId(id);
testData.setName(name);
return testData;
}
}
#Getter
#Setter
#ToString
class TestData{
private String name;
private int id;
}
Collection<Map<Item, Integer>> itemCollection = basket.values();
Iterator<Map<Item, Integer>> itemIterator = itemCollection.stream().sorted(new TestComparator()).collect(Collectors.toList()).iterator();
package com.ie.util;
import com.ie.item.Item;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class TestComparator implements Comparator<Map<Item, Integer>> {
// comparator is used to sort the Items based on the price
#Override
public int compare(Map<Item, Integer> o1, Map<Item, Integer> o2) {
// System.out.println("*** compare method will be called *****");
Item item1 = null;
Item item2 = null;
Set<Item> itemSet1 = o1.keySet();
Iterator<Item> itemIterator1 = itemSet1.iterator();
if(itemIterator1.hasNext()){
item1 = itemIterator1.next();
}
Set<Item> itemSet2 = o2.keySet();
Iterator<Item> itemIterator2 = itemSet2.iterator();
if(itemIterator2.hasNext()){
item2 = itemIterator2.next();
}
return -item1.getPrice().compareTo(item2.getPrice());
}
}
**** this is helpful to sort the nested map objects like Map> here i sorted based on the Item object price .
Using Comparator:
List<Type> result = list
.stream()
.sorted(Comparator.comparing(Type::getValue))
.collect(Collectors.toList());

How to sort a arraylist in java

Basically sorting could be done by following:
Collections.sort(List);
But my scenario is little bit different. I have a List which contains following objects.
Sample Code 1:
public class GetTraders {
private String getTraderLegalName;
private String businessName;
private Object status;
public GetTraders(String getTraderLegalName, String businessName, String status) {
this.getTraderLegalName=getTraderLegalName;
this.businessName=businessName;
this.status=status;
}
I have a class which will give value for above list as follow:
public Class getResult {
List<GetTraders> traders=new ArrayList<GetTraders>();
public void valueGivenByuser(String legal,String business,Object status)throws Exception {
GetTraders trade=new GetTraders(legal,business,status);
traders.add(trade); //Adding value to arrayList
}
}
The problem here is, once I added all values in traders arraylist I need to sort and display as output. I tried with collections.sort() but It shows compiler exception.
If you look closely to the Collections API, you will see that you have two options at your disposal:
1) make your GetTraders class implement the Comparable interface and call
public static <T extends Comparable<? super T>> void sort(List<T> list)
2) create a new Comparator for the GetTraders class and call
public static <T> void sort(List<T> list, Comparator<? super T> c)
The first solution is the easiest one but if you need to sort the GetTraders objects according to multiple criteria then the second one is the best choice.
As pointed out by #Vaseph, if you are using Java 8 instead, life suddenly becomes easier because all you need to do is:
traders.sort((GetTraders trade1, GetTraders trade2) -> {
return trade1.getBusinessName().compareTo(trade2.getBusinessName());
});
But if you are having troubles with the Comparable and Comparator interfaces, I would encourage you to first try the pre-Java-8 solutions before diving into the magic world of the functional interfaces.
For the sake of completeness, please also find below an example of each solution:
1) Comparable-based solution:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class GetTraders1 implements Comparable<GetTraders1> {
private String getTraderLegalName;
private String businessName;
private Object status;
public GetTraders1(String getTraderLegalName, String businessName, String status) {
this.getTraderLegalName=getTraderLegalName;
this.businessName=businessName;
this.status=status;
}
#Override
public int compareTo(GetTraders1 that) {
return this.getTraderLegalName.compareTo(that.getTraderLegalName);
}
#Override
public String toString() {
return "GetTraders [getTraderLegalName=" + getTraderLegalName + ", businessName=" + businessName + ", status=" + status + "]";
}
public static void main(String[] args) {
GetTraders1 getTraders1 = new GetTraders1("1", "bn", "status");
GetTraders1 getTraders2 = new GetTraders1("2", "bn", "status");
GetTraders1 getTraders3 = new GetTraders1("3", "bn", "status");
List<GetTraders1> list = new ArrayList<>();
list.add(getTraders3);
list.add(getTraders2);
list.add(getTraders1);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}
2) Comparator-based solution
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class GetTraders2 {
private String getTraderLegalName;
private String businessName;
private Object status;
public GetTraders2(String getTraderLegalName, String businessName, String status) {
this.getTraderLegalName=getTraderLegalName;
this.businessName=businessName;
this.status=status;
}
#Override
public String toString() {
return "GetTraders [getTraderLegalName=" + getTraderLegalName + ", businessName=" + businessName + ", status=" + status + "]";
}
public static void main(String[] args) {
GetTraders2 getTraders1 = new GetTraders2("1", "bn", "status");
GetTraders2 getTraders2 = new GetTraders2("2", "bn", "status");
GetTraders2 getTraders3 = new GetTraders2("3", "bn", "status");
List<GetTraders2> list = new ArrayList<>();
list.add(getTraders3);
list.add(getTraders2);
list.add(getTraders1);
System.out.println(list);
Collections.sort(list, new Comparator<GetTraders2>() {
#Override
public int compare(GetTraders2 o1, GetTraders2 o2) {
return o1.getTraderLegalName.compareTo(o2.getTraderLegalName);
}
});
System.out.println(list);
}
}
here is another way to sort list elements based on businessName:
traders.sort((GetTraders trade1, GetTraders trade2) -> {
return trade1.getBusinessName().compareTo(trade2.getBusinessName());
});
This hasn't be proposed but here it is.
You should use Collections#sort with a Comparator
Collections.sort(traders, (x, y) -> x.getXXX().compareTo(y.getXXX()));
// XXX could be any String object's getter
Use Comparator to determine order.
Collections.sort(someList, comparator);

Categories

Resources