get string using stream api - java

I have following code :
private String categoryId;
List<Category> categories = new List<>();
for(String category:categories){
if(category.getName().equals(categoryName)){
categoryId = category.getId();
break;
}
}
I want to use stream api here to get categoryId. My category class as follows.
class Category{
private String name;
private String id;
// gettters and setters.
}
category Id is assigned randomly when a new category is created.
Thanks in advance.

try to use this :
categoryId = categories.stream()
.filter(category -> category.getName().equals(categoryName))//filter by name
.map(Category::getId) //get only the ids
.findFirst() //return just the first result
.orElse(null); //if no result then return null

If you want to use Streams, you can write:
categories.stream().filter(c -> {
if (c.getName().equals(categoryName)) categoryId = c.getId()});

Related

Get the fields name that contain #Size annotation along with their max length

I have this entity -
#Entity
public class Employee{
#Id
#NotNull
#Size(max=5)
private Integer employeeId;
#NotNull
#Size(max=40)
private String employeeName;
private Long employeeSalary;
}
I want to get the name of the fields along with their maximum length allowed.
That is, for above case the output should be like
employeeId - 5
employeeName - 40
I have created this following which returns the name of the fields that contain #Size
public boolean hasSize() {
return Arrays.stream(this.getClass().getDeclaredFields())
.anyMatch(field -> field.isAnnotationPresent(Size.class));
}
public List<String> getSizeFields(){
if(hasSize()) {
Stream<Field> filter = Arrays.stream(this.getClass().getDeclaredFields())
.filter(field -> field.isAnnotationPresent(Size.class));
return filter.map(obj -> obj.getName()).collect(Collectors.toList());
}
else
return null;
}
Suggest me how can I get the max length of the fields as well.
Map<String, Integer> map = Stream.of(e.getClass().getDeclaredFields())
.filter(f -> f.isAnnotationPresent(Size.class))
.collect(Collectors.toMap(
f -> f.getName(),
f -> f.getAnnotation(Size.class).max()));

Returning boolean instead of list

user class with fields id, name and types
public class User {
private String id;
private String name;
private List<Types> types;
}
Types class with fields id, name , linkedTo
{
private String id;
private String name;
private String linkedTo;
}
Implemented a method to get types from user and return it as list
private List<Types> getType(List<User> Users) {
return Users
.stream()
.map(User::gettypes)
.flatMap(List::stream)
.collect(Collectors.toList());
}}
Now, have to map to response body. For that I have response class:
public class UserResponse {
private String id;
private String type;
private String name;
private String linkedTo;
}
Have to map the fields from Types to user response to return it as list
private List<UserResponse> getUserResponse(UserRequest request) {
List<User> Users = userServiceClient.getById();
List<UserResponse> userResponses = new ArrayList<>();
List<Types> TypesList = getType(Users);
if (!typesList.isEmpty()) {
return typesList.stream()
.map(type -> userResponses.add(new UserResponse( type.getGuid(),type.getName(),type.getName(),type.getLinkedTo())))
.collect(Collectors.toList());
}
return collections.emptylist();
}
Here is the problem, I'm not able to return it as list instead getting a boolean..
Is there any efficient way to do this? The code reviewer doesn't want me to use for each and return the list
A better appraoch would be
private List<UserResponse> getUserResponse(UserRequest request) {
List<User> Users = userServiceClient.getById();
List<Types> TypesList = getType(Users);
return typesList.stream()
.map(type -> new UserResponse(type.getId(), type.getName(), type.getName(), type.getLinkedTo()))
.collect(Collectors.toList());
}
Reason:
If typesList is empty, this would return empty List, as Collections.emptyList in your code.
It maps to the UserResponse objects and collects them to return the List<UserResponse> while using the Stream for it without the explicit instantiation and .add call.

How to search data in object and cast to list

I want to search value from object and convert result to list
I tried to get data object name "data" and i want to search every item that has "querytext".How to convert object data to List
public class SimpleMovieSearchService implements MovieSearchService {
#Autowired
private MovieDataService movieDataService;
#Override
public List<Movie> search(String queryText) {
MoviesResponse data =movieDataService.fetchAll();
List<Movie> result = data.stream() // problem in this line
.filter(item -> item.getTitle().equals("queryText"))
.collect(Collectors.toList());
return result;
}
}
MovieData.java
public class MovieData {
private String title;
private int year;
private List<String> cast;
private List<String> genres;
getter and setter
}
Movie.java
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ElementCollection(fetch = FetchType.EAGER)
private List<String> actors = new ArrayList<>();
getter and setter
}
edit
MovieResponse.java
public class MoviesResponse extends ArrayList<MovieData> {
}
MovieDataService.java
public interface MovieDataService {
MoviesResponse fetchAll();
}
Type of data i got is List of MovieData but i want result in List of Movie how to fix this or another way to do.and without change anything in Movie.java or MovieData.java
Update
now i can do with this way
MoviesResponse a = movieDataService.fetchAll();
List<Movie> result = a.stream()
.map(movie -> new Movie(movie.getTitle()))
.filter(movie -> movie.getName().equals(queryText)) //this line
.collect(Collectors.toList());
if data are "banana" ,"nature" , "red" and then query text is "na" i want result are "banana" and "nature".in sql in situation it can use "like".How to use "like" with this filter ?
Try to use stream map
data.stream() // problem in this line
.filter(item -> item.getTitle().equals("queryText"))
.map(movie -> {
//logic to transform MovieResponse in Movie here
})
.collect(Collectors.toList());
See more in: https://dzone.com/articles/how-to-use-map-filter-collect-of-stream-in-java-8
Instead of fetching all movies and filer them by stream, write a method that queries the ones you want.
Something like
SELECT * FROM movies WHERE title = 'queryText'
Depending on your code/framework, you have to implement this or just have to choose another method in you MovieDataService.

Why toString method won't get the selected item in JComboBox?

I bind my values from database to JComboBox using ArrayList and converted each array using StringBuilder because StringBuilder accepts any data types so I think this is the most efficient way.
while(rs.next())
{
departmentId = rs.getInt(1);
departmentTypeList = rs.getString(2);
ArrayList<DepartmentList> listDepartment = new ArrayList<DepartmentList>();
listDepartment.add(new DepartmentList(departmentId,departmentTypeList));
StringBuilder builder = new StringBuilder();
for(DepartmentList s : listDepartment)
{
builder.append(s);
}
cbDepartmentType.addItem(builder.toString());
}
private class DepartmentList
{
private int id;
private String department;
private DepartmentList(int id,String department)
{
this.id = id;
this.department = department;
}
private int getId()
{
return id;
}
#Override
public String toString() //Converting to String the (departmentId,departmentTypeList)
{
return department;
}
}
I added a listener on my JComboBox to listen what item is selected. I already converted my class to Object but when I click the JComboBox it gives me a exception java.lang.String Any ways to solve this problem?
if(e.getSource() == cbDepartmentType)
{
DepartmentList item = (DepartmentList) cbDepartmentType.getSelectedItem();
System.out.println("id "+(item.getId()));
}
StackTrace:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.String cannot be cast to position.AddPosition$DepartmentList
at position.AddPosition$ItemHandler.actionPerformed(AddPosition.java:295)
at javax.swing.JComboBox.fireActionEvent(JComboBox.java:1258)
at javax.swing.JComboBox.setSelectedItem(JComboBox.java:586)
at javax.swing.JComboBox.setSelectedIndex(JComboBox.java:622)
Update:
while(rs.next())
{
departmentId = rs.getInt(1);
departmentTypeList = rs.getString(2);
ArrayList<DepartmentList> listDepartment = new ArrayList<DepartmentList>();
listDepartment.add(new DepartmentList(departmentId,departmentTypeList));
cbDepartmentType.addItem(listDepartment.toString());
}
You are adding String to the Combobox
cbDepartmentType.addItem(builder.toString());
And you try to cast the selected item into a DepartementList
DepartmentList item = (DepartmentList) cbDepartmentType.getSelectedItem();
But you get a String. So something like this is try to run.
DepartmentList item = (DepartmentList) "A string";
You can add DepartmentList to the comboxbox directly.
cbDepartmentType.addItem(departement);
This will use the implementation of toString() of DepartementList to print the text in the component.
With this, the selectedItem will be an instance of DepartementList.
Here is the official tutorial of How to use Combo Boxes
EDIT :
Your code should look like :
while(rs.next())
{
departmentId = rs.getInt(1);
departmentTypeList = rs.getString(2);
DepartmentList dep = new DepartmentList(departmentId,departmentTypeList); //Create a department
cbDepartmentType.addItem(dep ); //insert into the combo
}
In your original code, you were using a List to store the instance then recover this instance to parse it into a StringBuilder then insert this represention (a String) into the combobox.
My logic
Department -> Combobox
Yours
List > Departemnt > StringBuilder > Combobox
Try to understand the while loop you had, you will see this was not logic at all.

How to use Java 8 Streams groupingBy to map multiple database records to a single object with a List<String> property for one column

My problem essentially comes down to this simplified example. I have data coming back from a DB which has some duplicate information in the rows.
In this example I have a list of TeamRow objects that come back from the DB. I can easily group these using Collectors.groupingBy:
public class TeamRow {
private int id;
private String name;
private String player;
public TeamRow(int id, String name, String player) {
this.id = id;
this.name = name;
this.player = player;
}
public int getId() {return id;}
public String getName() { return name; }
public String getPlayer() {return player;}
}
public class Team {
private int id;
private String name;
private List<String> players;
public Team(int id, String name, List<String> players) {
this.id = id;
this.name = name;
this.players = new ArrayList<String>(players);
}
}
List<TeamRow> dbTeams = new ArrayList<TeamRow>();
dbTeams.add(new TeamRow(1, "Team1", "Jonny"));
dbTeams.add(new TeamRow(1, "Team1", "Rob"));
dbTeams.add(new TeamRow(1, "Team1", "Carlos"));
dbTeams.add(new TeamRow(2, "Team2", "Shane"));
dbTeams.add(new TeamRow(2, "Team2", "Lucas"));
dbTeams.add(new TeamRow(3, "Team3", "Geraint"));
dbTeams.add(new TeamRow(3, "Team3", "Rocky"));
dbTeams.add(new TeamRow(3, "Team3", "Wayne"));
dbTeams.add(new TeamRow(3, "Team3", "Dwayne"));
dbTeams.add(new TeamRow(3, "Team3", "Lester"));
Map<Integer, List<TeamRow>> myMap = dbTeams.stream().collect(Collectors.groupingBy(TeamRow::getId));
However, what I'm actually trying to achieve is to convert the TeamRows to Teams. So that the id and name are only represented once and the players are stored in a List in the Team object. I can achieve this by adding a forEach over the map as shown below.
But I've been trying to figure out if there is a way I can achieve the same result by adding some sort of mapper or downstream collector. Would this even offer any benefit over adding a subsequent forEach ?? Eg:
List<Team> teams = dbTeams.stream().collect(Collectors.groupingBy(TeamRow::getId, ???), ???).???;
Conversion using forEach:
List<Team> teams = new ArrayList<>();
myMap.forEach((id, teamRows) -> {
if (teamRows.size() > 0) {
TeamRow tr = teamRows.get(0);
List<String> players = teamRows.stream().map(TeamRow::getPlayer).collect(Collectors.toList());
teams.add(new Team(id, tr.getName(), players));
}
});
Previously I said I would do it by creating an atomic transformer function like this:
Function<TeamRow, Team> getTeamRowTransformer() {
final Map<Integer, Team> map = new ConcurrentHashMap<Integer, Team>();
return (teamRow)->{
Team result = map.computeIfAbsent(teamRow.getId(), id->new Team(id, teamRow.getName(), Collections.emptyList()));
result.players.add(teamRow.getPlayer());
return result;
};
}
It handles the mapping and your stream code becomes one very legible step:
Set<Team> finalTeams = dbTeams.stream()
.map(getTeamRowTransformer())
.collect(Collectors.toSet());
HOWEVER, I realized, you can also do this:
List<Team> teams = dbTeams.stream()
.map(tr->new Team(tr.getId(), tr.getName(), Arrays.asList(tr.getPlayer())))
.collect(Collectors.collectingAndThen(
Collectors.groupingBy(t->t.id,
Collectors.reducing((Team a, Team b)->{
a.players.addAll(b.players);
return (Team)a;
})
), m->m.values().stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList())
)
);
This way you never have an accessible mutable collection until List<Team> teams is assigned.
You may use toMap collector with custom merge function. It's probably a good idea to add merge method to the Team class:
public class Team {
private final int id;
private final String name;
private final List<String> players;
public Team(int id, String name, List<String> players) {
this.id = id;
this.name = name;
this.players = new ArrayList<>(players);
}
// merges other team into this team, returning this team
public Team merge(Team other) {
assert id == other.id; // remove asserts if you don't like them
assert name.equals(other.name);
players.addAll(other.players);
return this;
}
}
Now you can solve your problem this way:
Collection<Team> teams = dbTeams.stream()
.map(tr -> new Team(tr.id, tr.name, Arrays.asList(tr.player)))
.collect(Collectors.toMap(t -> t.id, t -> t, Team::merge)).values();
You could try something like
List<Team> teamList = dbTeams.stream().collect(Collectors.collectingAndThen(Collectors.groupingBy(TeamRow::getId),
(m -> m.entrySet().stream().map(
e -> {
List<TeamRow> l = e.getValue();
return new Team(l.get(0).getId(), l.get(0).getName(), l.stream().map(TeamRow::getPlayer).collect(Collectors.toList()));
}
).collect(Collectors.toList()))));
Using collectingAndThen() you can use a function which maps the entries of the map to Teams. l.get(0) should not fail as there is always at least one entry in the list.
I am not sure if this is more concise, but at least it does not use foreach.

Categories