Let say I have the Student
class:
public class Student {
private String id;
private String firstName;
private String lastName;
//gettter and setter
}
I will have list of Student
:
List<Student> list; //this includes all students
Now, when i retrieve Student
details object, I will just have the id
and need to check whether this id
exists in list provided above or not. I can easily achieve this with simple java like this: creating one method which will take the list and student id
as parameters and checking whether it is there in the list or not:
public static boolean valueExistInList(List<Student> list, String studentId) {
if (StringUtils.isNotBlank(studentId)) {
for (Student stu : list) {
if (studentId.equals(stu.getId())) {
return true;
}
}
}
return false;
}
But my question is: can I also achieve same kind of functionality with Java generics
method that will take list of any type of object and single value parameter(String or Integer
or BigDecimal
or BigInteger
) and checks whether single parameter exists in list or not and return boolean value?
Any help will be appreciated. Thanks
I am thinking if i can have method like this:
public static <T, U> boolean valueExistInList(List<T> list, U studentId) {
boolean exists = false;
//looping and checing whether studentId exists in list or not and
//then returning boolean value
for(T t: list){
//check studentId exists in list or not
//if exists then return exists = true
return exists;
}
return exists;
}
Your main problem with this generic method approach is that you do not know which method to call on each list element for checking. Additionally, you easily can imagine other boolean tests, not only equals
(and not only on strings).
So you could go another step back: Let the caller of your method decide what boolean test should be made in the loop. You could express this as an interface:
interface BooleanExpression<T> { boolean test(T arg); }
Your generic method now changes to:
public static <T, U> boolean valueExistInList(List<T> list, BooleanExpression<T> tester) {
for(T t: list) {
if (tester.test(t)) return true;
}
return false;
}
You now can call this method as such:
List<Student> list = ...
final String studentId = ...
boolean result = valueExistsInList(list, new BooleanExpression<Student>() {
@Override public boolean test(Student arg) {
return arg.getId().equals(studentId);
}
});
Having said this ... Java 8 provides such an interface. It is called a Predicate
. And it nicely fits into the new Stream API . So you now can write
List<Student> list = ...
String studentId = ...
boolean result = list.stream().anyMatch(s -> s.getId().equals(studentId));
You can in combination with functions.
public static <T> boolean valueExistInList(List<T> list, Predicate<T> predicate) {
return list.stream().anyMatch(predicate);
}
You can call it like this:
valueExistsInList(students, s -> s.getId().equals(studentId));
Or:
valueExistsInList(cars, c -> c.getBrand().equals("Tesla"));
In fact, you can do this even without a function, more directly like this:
boolean exists = students.stream().anyMatch(s -> s.getId().equals(studentId));
Java 7
public interface Predicate<T> {
boolean test(T t);
}
Then call your function like this:
valueExistInList(students, new Predicate<Student>() {
boolean test(Student s) {
return s.getId().equals(studentId);
}
});
And the function valueExistsInList
then becomes:
public static <T> boolean valueExistInList(List<T> list, Predicate<T> predicate) {
for (T t : list) {
if (predicate.test(t)) {
return true;
}
}
return false;
}
List is an extension from the java Collection interface so you can do a lot of customizing by overriding the equals method so your contains method will function as you'd like. You would end up doing something like this:
@Override
public boolean equals(Object o){
if(o instanceof String){
String toCompare = (String) o;
return id.equals(toCompare);
}
return false;
}
Please check the (working) example below. By letting Student
override from ObjectWithId<U>
where U
is the type of the id, you can have generic methods to check for the ids (in the Util class)
public class Test
{
public static void main(String[] args){
Student s = new Student();
s.setId("studentId1");
System.out.println(Util.hasCorrectId(s, "studentId1"));
}
}
public class ObjectWithId<U>
{
private U id;
public U getId(){
return id;
}
public void setId(U id){
this.id = id;
}
}
public class Student extends ObjectWithId<String>
{
}
public class Util {
public static <U> boolean valueExistInList(List<ObjectWithId<U>> list, U id) {
for (ObjectWithId<U> obj : list) {
if(hasCorrectId(obj, id)) return true;
}
return false;
}
public static <U> boolean hasCorrectId(ObjectWithId<U> obj, U id){
return id.equals(obj.getId());
}
}
You can have something like this
public static <T, U> boolean valueExistInList(List<T> list, U input) {
for(T t: list)
{
if (input.equals(t.getU)) // getU method should be there in T
return true;
}
return false;
}
But you have to be careful while passing custom types. You have to override equals method.
Although this will work fine for types like String
, Integer
etc where equals
is already overriden.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.