เพรดิเคตใน Java


101

ฉันกำลังอ่านโค้ดที่ใช้Predicateใน Java ฉันไม่เคยใช้Predicate. มีใครช่วยแนะนำฉันเกี่ยวกับบทช่วยสอนหรือคำอธิบายแนวความคิดPredicateและการนำไปใช้ใน Java ได้ไหม


4
คุณกำลังพูดถึงฝรั่งPredicateหรือเปล่า? สิ่งที่คล้ายกัน? อย่างอื่นทั้งหมด?
polygenelubricants

2
นอกจากนี้ยังมี Apache CommonsPredicate
Dan Gravell

คำตอบ:


203

ฉันสมมติว่าคุณกำลังพูดถึงcom.google.common.base.Predicate<T>จากฝรั่ง

จาก API:

กำหนดtrueหรือfalseค่าสำหรับอินพุตที่กำหนด ตัวอย่างเช่นRegexPredicateอาจใช้Predicate<String>และส่งคืนจริงสำหรับสตริงใด ๆ ที่ตรงกับนิพจน์ทั่วไปที่กำหนด

โดยพื้นฐานแล้วนี่คือนามธรรม OOP สำหรับการbooleanทดสอบ

ตัวอย่างเช่นคุณอาจมีวิธีการช่วยเหลือดังนี้

static boolean isEven(int num) {
   return (num % 2) == 0; // simple
}

ตอนนี้ให้ a List<Integer>คุณสามารถประมวลผลเฉพาะเลขคู่ดังนี้:

    List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    for (int number : numbers) {
        if (isEven(number)) {
            process(number);
        }
    }

ด้วยPredicateการifทดสอบจะแยกออกเป็นประเภท สิ่งนี้ช่วยให้สามารถทำงานร่วมกับส่วนที่เหลือของ API ได้เช่นIterablesซึ่งมีวิธีการยูทิลิตี้มากมายที่ใช้Predicateซึ่งมีวิธีการสาธารณูปโภคหลายอย่างที่ต้องใช้เวลา

ดังนั้นตอนนี้คุณสามารถเขียนสิ่งนี้:

    Predicate<Integer> isEven = new Predicate<Integer>() {
        @Override public boolean apply(Integer number) {
            return (number % 2) == 0;
        }               
    };
    Iterable<Integer> evenNumbers = Iterables.filter(numbers, isEven);

    for (int number : evenNumbers) {
        process(number);
    }

โปรดทราบว่าตอนนี้สำหรับแต่ละลูปนั้นง่ายขึ้นมากโดยไม่ต้องifทดสอบ เรามาถึงระดับที่สูงขึ้นของการลบล้างโดยการกำหนดIterable<Integer> evenNumbersโดยfilterใช้ a Predicate.

ลิงค์ API

  • Iterables.filter
    • ส่งคืนองค์ประกอบที่ตรงตามเพรดิเคต

ในฟังก์ชันลำดับที่สูงขึ้น

Predicateอนุญาตให้Iterables.filterทำหน้าที่เป็นสิ่งที่เรียกว่าฟังก์ชันลำดับที่สูงขึ้น ด้วยตัวมันเองสิ่งนี้มีข้อดีมากมาย ใช้List<Integer> numbersตัวอย่างข้างต้น สมมติว่าเราต้องการทดสอบว่าตัวเลขทั้งหมดเป็นบวกหรือไม่ เราสามารถเขียนสิ่งนี้:

static boolean isAllPositive(Iterable<Integer> numbers) {
    for (Integer number : numbers) {
        if (number < 0) {
            return false;
        }
    }
    return true;
}

//...
if (isAllPositive(numbers)) {
    System.out.println("Yep!");
}

ด้วย a Predicateและทำงานร่วมกับไลบรารีที่เหลือเราสามารถเขียนสิ่งนี้แทน:

Predicate<Integer> isPositive = new Predicate<Integer>() {
    @Override public boolean apply(Integer number) {
        return number > 0;
    }       
};

//...
if (Iterables.all(numbers, isPositive)) {
    System.out.println("Yep!");
}

หวังว่าตอนนี้คุณจะเห็นค่าใน abstractions ที่สูงขึ้นสำหรับรูทีนเช่น "กรององค์ประกอบทั้งหมดตามเพรดิเคตที่กำหนด" "ตรวจสอบว่าองค์ประกอบทั้งหมดตรงตามเพรดิเคตที่กำหนดหรือไม่" ฯลฯ ทำให้โค้ดดีขึ้น

แต่น่าเสียดายที่ Java ไม่ได้มีวิธีการชั้นแรก: คุณไม่สามารถผ่านวิธีรอบและIterables.filter Iterables.allแน่นอนคุณสามารถส่งผ่านวัตถุใน Java ได้ ดังนั้นPredicateประเภทจึงถูกกำหนดและคุณส่งผ่านอ็อบเจ็กต์ที่ใช้อินเทอร์เฟซนี้แทน

ดูสิ่งนี้ด้วย


4
ฉันไม่ได้อ้างถึง Predicate ของ Guava ฉันควรจะชัดเจนในคำถามของฉัน แต่คำอธิบายของคุณช่วยให้ฉันเข้าใจสิ่งที่ฉันกำลังมองหาวิธีการใช้ตรรกะเพรดิเคตใน java ขอบคุณสำหรับคำอธิบายอย่างละเอียด
srikanth

@polygenelubricants ทำไมต้องคิดค้นPredicate<Integer>เมื่อเรามีF<Integer, Boolean>สิ่งที่เหมือนกันแล้ว?
Pacerier

คุณสามารถทำได้ด้วยวิธีของ java 8: List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Predicate<Integer> isEven = integer -> (integer % 2) == 0; Iterable<Integer> evenNumbers = numbers.stream().filter(isEven).collect(Collectors.toList());

14

เพรดิเคตคือฟังก์ชันที่ส่งกลับค่าจริง / เท็จ (เช่นบูลีน) ซึ่งตรงข้ามกับประพจน์ซึ่งเป็นค่าจริง / เท็จ (เช่นบูลีน) ใน Java เราไม่สามารถมีฟังก์ชันแบบสแตนด์อโลนได้ดังนั้นจึงสร้างเพรดิเคตโดยการสร้างอินเทอร์เฟซสำหรับอ็อบเจ็กต์ที่แสดงถึงเพรดิเคตจากนั้นจึงมีคลาสที่ใช้อินเทอร์เฟซนั้น ตัวอย่างของอินเทอร์เฟซสำหรับเพรดิเคตอาจเป็น:

public interface Predicate<ARGTYPE>
{
    public boolean evaluate(ARGTYPE arg);
}

จากนั้นคุณอาจมีการใช้งานเช่น:

public class Tautology<E> implements Predicate<E>
{
     public boolean evaluate(E arg){
         return true;
     }
}

เพื่อให้เข้าใจแนวคิดที่ดีขึ้นคุณอาจต้องการอ่านเกี่ยวกับตรรกะลำดับที่หนึ่ง

แก้ไข
มีอินเทอร์เฟซPredicateมาตรฐาน( java.util.function.Predicate ) ที่กำหนดไว้ใน Java API เป็น Java 8 ก่อน Java 8 คุณอาจพบว่าสะดวกในการนำอินเตอร์เฟสcom.google.common.baseมาใช้ซ้ำจากฝรั่ง .

นอกจากนี้โปรดทราบว่าใน Java 8 นั้นง่ายกว่ามากในการเขียนเพรดิเคตโดยใช้ lambdas ตัวอย่างเช่นใน Java 8 ขึ้นไปเราสามารถส่งผ่านp -> trueไปยังฟังก์ชันแทนที่จะกำหนดคลาสย่อย Tautology ที่มีชื่อเหมือนข้างต้น


0

คุณสามารถดูตัวอย่างjava docหรือตัวอย่างการใช้งาน Predicate ได้ที่นี่

โดยทั่วไปจะใช้เพื่อกรองแถวในชุดผลลัพธ์ตามเกณฑ์เฉพาะใด ๆ ที่คุณอาจมีและส่งคืนค่าจริงสำหรับแถวที่ตรงตามเกณฑ์ของคุณ:

 // the age column to be between 7 and 10
    AgeFilter filter = new AgeFilter(7, 10, 3);

    // set the filter.
    resultset.beforeFirst();
    resultset.setFilter(filter);

ฉันกำลังอ้างถึงเพรดิเคตคอมมอนส์ไม่ใช่ผลลัพธ์ที่เกี่ยวข้อง ขอบคุณ
srikanth

0

การเพิ่มสิ่งที่Michealพูด:

คุณสามารถใช้ Predicate ดังต่อไปนี้ในการกรองคอลเลกชันใน java:

public static <T> Collection<T> filter(final Collection<T> target,
   final Predicate<T> predicate) {
  final Collection<T> result = new ArrayList<T>();
  for (final T element : target) {
   if (predicate.apply(element)) {
    result.add(element);
   }
  }
  return result;
}

เพรดิเคตหนึ่งที่เป็นไปได้คือ:

final Predicate<DisplayFieldDto> filterCriteria = 
                    new Predicate<DisplayFieldDto>() {
   public boolean apply(final DisplayFieldDto displayFieldDto) {
    return displayFieldDto.isDisplay();
   }
  };

การใช้งาน:

 final List<DisplayFieldDto> filteredList=
 (List<DisplayFieldDto>)filter(displayFieldsList, filterCriteria);

1
นั่นไม่เป็นการเอาชนะจุดประสงค์โดยพื้นฐานหรือไม่? เหตุผลหลักในการเลือกวิธีการทำงานคือการไม่ทำซ้ำด้วยตนเองและกำจัดสำหรับ. ระดับของสิ่งที่เป็นนามธรรมจะสูงขึ้นและมีพลังมากขึ้น - อย่างไรก็ตามการทำเพื่อเอาชนะจุดประสงค์นั้นด้วยตนเองและกลับสู่นามธรรมระดับต่ำ
Eugen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.