In C++, I can use find_if
with a predicate to find an element in a container. Is there something like that in Java? The contains
method on collections uses equals and can not be parameterized.
views:
234answers:
4You can use Predicate from Google Collections. Here is the tutorial and an example from it:
final Predicate<Car> expensiveCar = new Predicate<Car>() {
public boolean apply(Car car) {
return car.price > 50000;
}
}
List<Car> cars = Lists.newArrayList();
cars.add(new Car("Ford Taurus", 20000));
cars.add(new Car("Tesla", 90000));
cars.add(new Car("Toyota Camry", 25000));
cars.add(new Car("McClaren F1", 600000));
finalList<Car> premiumCars =
Lists.immutableList(Iterables.filter(cars, expensiveCar));
You can also look at this thread: What is the best way to filter a Collection?
You can use CollectionUtils.select from Apache Commons.
For example, the following C++ code
bool isOdd (int i) {
return i % 2 != 0;
}
...
vector<int> myvector;
vector<int>::iterator it;
myvector.push_back(10);
myvector.push_back(25);
myvector.push_back(40);
myvector.push_back(55);
it = find_if (myvector.begin(), myvector.end(), isOdd);
cout << "The first odd value is " << *it << endl;
can be written in Java as,
List<Integer> myList = Arrays.asList(10, 25, 40, 55);
List<Integer> oddNums = (List<Integer>) CollectionUtils.select(myList,
new Predicate<Integer>() {
public boolean apply(Integer i) {
return i % 2 != 0;
}
}
);
System.out.println("The first odd value is "+oddNums.get(0));
Please note that, unlike in C++ example, this would create a new list of the elements satisfying the specified predicate.
EDIT :
As Matthew Flaschen has suggested in a comment below, CollectionUtils.find is even closer to what you need. So, with find
, the above code can be rewritten as:
List<Integer> myList = Arrays.asList(10, 25, 40, 55);
Integer firstOdd = (Integer) CollectionUtils.find(myList,
new Predicate<Integer>() {
public boolean apply(Integer i) {
return i % 2 == 1;
}
}
);
System.out.println("The first odd value is "+firstOdd);
By using lambdaj you can easily filter a java collection in a very readable way. For example the following statement:
select(persons, having(on(Person.class).getAge(), greaterThan(30)));
selects all the persons in your list having more than 30 years.
The problem is that using a method like find_if should make the code simpler to write and easier to read. However, IMHO Java does not lend itself to functional notation and most of the time it is clearer and simpler to just write a natural loop. i.e. the code is shorter and doesn't require knowledge of libraries most people don't use. If this functionality was built in and Java supported Closures (as it appears Java 7 will) then using predicates and functional methods would make more sense.
One measure of complexity is to count the number of symbols (counting open/close brackets as one) Using this measure of complexity, most predicate based solutions have more symbols and are possibly more complex and difficult for developers to read/maintain.
In the example given by @Roman, there are 15 symbols. In the loop example, there are 10 symbols.
List<Car> premiumCars = new ArrayList();
for(Car car: cars)
if(car.price > 50000)
premiumCars.add(car);
In the example by @Mario Fuscom, there is 9 symbols, in the following example there is 9 symbols. However, no non-standard functions are required and anyone who knows Java can read/maintain it.
List peopleOver30 = new ArrayList();
for(Person person: people)
if(person.age > 30)
peopleOver30.add(person);
Taking the last example from @Rahul G - I hate Unicorns, there are 13 symbols. In the loop example, there are 8 symbols.
Integer firstOdd = null;
for(int i: myList)
if(i % 2 == 1) {
firstOdd = i;
break;
}
Functional programming may make more sense to you because that is your development background, but this doesn't mean it is the natural or simplest way to express this in Java. Java 7 may change this....