2010-04-05 38 views
7

Trong C++, tôi có thể sử dụng find_if với biến vị ngữ để tìm một phần tử trong vùng chứa. Có cái gì đó như thế trong Java? Phương thức contains trên bộ sưu tập sử dụng bằng và không thể tham số hóa.Có điều gì đó giống như find_if trong Java không?

+0

Sự cống hiến là những gì đến với tâm chk http://commons.apache.org/collections/api-2.1.1/org/apache/commons/collections/class-use/Predicate .html – Narayan

+1

Ngoài ra, hãy xem http://code.google.com/p/google-collections, đặc biệt là các giao diện vị ngữ và chức năng. – gpampara

Trả lời

11

Bạn có thể sử dụng Predicate từ Google Collections. Đây là tutorial và một ví dụ từ nó:

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)); 

final List<Car> premiumCars = 
    Lists.immutableList(Iterables.filter(cars, expensiveCar)); 

Bạn cũng có thể xem chủ đề này: What is the best way to filter a Collection?

+0

'Iterables.find' (http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Iterables.html#find%28java.lang.Iterable,%20com.google. common.base.Predicate% 29) sẽ chỉ cung cấp phần tử khớp đầu tiên. –

+0

@Matthew Flaschen: vâng, nếu chúng ta chỉ cần nhận được ít nhất 1 mục tương ứng thì 'Iterables.find' sẽ là giải pháp tốt nhất. – Roman

+0

Tôi nghĩ rằng bạn đang sử dụng ảnh chụp nhanh trước khi phát hành của Google Bộ sưu tập! Nếu bạn muốn sao chép các iterable lọc vào một danh sách bất biến (như trái ngược với chỉ looping thông qua nó trực tiếp), sử dụng ImmutableList.copyOf(). –

2

Bạn có thể sử dụng CollectionUtils.select từ Apache Commons.

Ví dụ, C sau ++ mã

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; 

có thể được viết bằng Java như,

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)); 

Xin lưu ý rằng, không giống như trong C++ ví dụ, điều này sẽ tạo ra một danh sách mới của các yếu tố thỏa mãn vị từ được chỉ định.

EDIT:

Như Matthew Flaschen đã gợi ý trong một chú thích dưới đây, CollectionUtils.find thậm chí còn gần gũi hơn với những gì bạn cần. Như vậy, với find, mã trên có thể được viết lại như sau:

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); 
+0

CollectionUtils.find (http://commons.apache.org/collections/apidocs/org/apache/commons/collections/CollectionUtils.html#find%28java.util.Collection,%20org.apache.commons.collections.Predicate% 29) thậm chí còn gần hơn; nó chỉ trả về phần tử khớp đầu tiên. –

+0

@Matthew: Cảm ơn. Đã cập nhật câu trả lời để bao gồm điều đó. – missingfaktor

+0

Không bao giờ sử dụng bộ sưu tập apache trừ khi bạn đã có trong java 1.4.2 hoặc thấp hơn. – KitsuneYMG

0

Bằng cách sử dụng lambdaj bạn có thể dễ dàng lọc một bộ sưu tập java một cách rất dễ đọc. Ví dụ: tuyên bố sau:

select(persons, having(on(Person.class).getAge(), greaterThan(30))); 

chọn tất cả những người trong danh sách của bạn có hơn 30 năm.

1

Vấn đề là sử dụng phương thức như find_if sẽ làm cho mã đơn giản hơn để viết và dễ đọc hơn. Tuy nhiên, IMHO Java không cho vay chính nó với ký pháp chức năng và phần lớn thời gian nó rõ ràng và đơn giản hơn để chỉ viết một vòng lặp tự nhiên. tức là mã ngắn hơn và không yêu cầu kiến ​​thức về thư viện mà hầu hết mọi người không sử dụng. Nếu chức năng này được xây dựng và hỗ trợ Java đóng cửa (như nó xuất hiện Java 7 sẽ) sau đó sử dụng vị từ và phương pháp chức năng sẽ có ý nghĩa hơn. Một số đo độ phức tạp là đếm số biểu tượng (đếm mở/đóng dấu ngoặc đơn) Sử dụng biện pháp phức tạp này, hầu hết các giải pháp dựa trên vị ngữ có nhiều ký hiệu hơn và có thể phức tạp và khó khăn hơn cho các nhà phát triển để đọc/duy trì .

Trong ví dụ được đưa ra bởi @Roman, có 15 ký hiệu. Trong ví dụ vòng lặp, có 10 biểu tượng.

List<Car> premiumCars = new ArrayList(); 
for(Car car: cars) 
    if(car.price > 50000) 
     premiumCars.add(car); 

Trong ví dụ bằng @Mario Fuscom, có 9 ký hiệu, trong ví dụ sau có 9 ký hiệu. Tuy nhiên, không có chức năng phi tiêu chuẩn nào được yêu cầu và bất kỳ ai biết Java có thể đọc/duy trì nó.

List peopleOver30 = new ArrayList(); 
for(Person person: people) 
    if(person.age > 30) 
     peopleOver30.add(person); 

Lấy ví dụ cuối cùng từ @Rahul G - Tôi ghét Unicorns, có 13 ký hiệu. Trong ví dụ vòng lặp, có 8 ký hiệu.

Integer firstOdd = null; 
for(int i: myList) 
    if(i % 2 == 1) { 
     firstOdd = i; 
     break; 
    } 

Lập trình chức năng có thể có ý nghĩa hơn với bạn vì đó là nền tảng phát triển của bạn, nhưng điều này không có nghĩa là cách tự nhiên hoặc đơn giản nhất để thể hiện điều này trong Java. Java 7 có thể thay đổi điều này ....

+0

Phản hồi tốt Peter. Tôi đã thử sử dụng một phong cách chức năng trong Java, và cũng đã phát hiện ra nó làm cho mã phức tạp hơn, và khó hiểu hơn. –

Các vấn đề liên quan