Predicado em Java

100

Estou passando pelo código que usa Predicateem Java. Eu nunca usei Predicate. Alguém pode me orientar para algum tutorial ou explicação conceitual Predicatee sua implementação em Java?

srikanth
fonte
4
Tá falando da goiaba Predicate? Alguma coisa similar? Algo totalmente diferente?
poligenelubrificantes de
2
Há também Apache CommonsPredicate
Dan Gravell

Respostas:

203

Presumo que você esteja falando com.google.common.base.Predicate<T>da Goiaba.

Da API:

Determina um valor trueou falsepara uma determinada entrada. Por exemplo, a RegexPredicatepode implementar Predicate<String>e retornar true para qualquer string que corresponda à sua expressão regular fornecida.

Esta é essencialmente uma abstração OOP para um booleanteste.

Por exemplo, você pode ter um método auxiliar como este:

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

Agora, dado um List<Integer>, você pode processar apenas os números pares como este:

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

Com Predicate, o ifteste é abstraído como um tipo. Isso permite que ele interopere com o resto da API, como, por exemplo Iterables, que tem muitos métodos de utilitário necessários Predicate.

Assim, agora você pode escrever algo assim:

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

Observe que agora o loop for-each é muito mais simples sem o ifteste. Alcançamos um nível mais alto de abtração definindo Iterable<Integer> evenNumbers, filter-ing usando a Predicate.

Links de API


Na função de ordem superior

Predicatepermite Iterables.filterservir como o que é chamado de função de ordem superior. Por si só, isso oferece muitas vantagens. Veja o List<Integer> numbersexemplo acima. Suponha que desejamos testar se todos os números são positivos. Podemos escrever algo assim:

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

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

Com um Predicatee interoperando com o resto das bibliotecas, podemos escrever isto:

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

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

Esperançosamente, agora você pode ver o valor em abstrações mais altas para rotinas como "filtrar todos os elementos pelo predicado fornecido", "verificar se todos os elementos satisfazem o predicado fornecido", etc., para criar um código melhor.

Infelizmente, Java não tem métodos de primeira classe: você não pode passar métodos para Iterables.filtere Iterables.all. Você pode, é claro, passar objetos em Java. Portanto, o Predicatetipo é definido e você passa os objetos que implementam essa interface.

Veja também

poligenelubrificantes
fonte
4
Eu não estava me referindo ao Predicado de Guava, deveria ter sido claro em minha pergunta. Mas sua explicação me ajudou a entender o que eu estava procurando, a forma como a lógica de predicado é usada em java. Obrigado pela explicação elaborada
srikanth
@polygenelubricants, Por que inventar Predicate<Integer>quando já temos o F<Integer, Boolean>que faz exatamente a mesma coisa?
Pacerier de
Você também pode fazer isso da maneira 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

Um predicado é uma função que retorna um valor verdadeiro / falso (ou seja, booleano), ao contrário de uma proposição que é um valor verdadeiro / falso (ou seja, booleano). Em Java, não se pode ter funções autônomas e, portanto, cria-se um predicado criando uma interface para um objeto que representa um predicado e, em seguida, fornece-se uma classe que implementa essa interface. Um exemplo de interface para um predicado pode ser:

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

E então você pode ter uma implementação como:

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

Para obter uma melhor compreensão conceitual, você pode querer ler sobre lógica de primeira ordem.

Editar
Há uma interface Predicate padrão ( java.util.function.Predicate ) definida na API Java a partir de Java 8. Antes do Java 8, você pode achar conveniente reutilizar a interface com.google.common.base.Predicate de Goiaba .

Além disso, observe que a partir do Java 8, é muito mais simples escrever predicados usando lambdas. Por exemplo, no Java 8 e superior, pode-se passar p -> truepara uma função em vez de definir uma subclasse Tautology nomeada como a acima.

Michael Aaron Safyan
fonte
0

Você pode ver os exemplos de documentos java ou o exemplo de uso de Predicate aqui

Basicamente, é usado para filtrar linhas no conjunto de resultados com base em qualquer critério específico que você possa ter e retornar verdadeiro para as linhas que atendem aos seus critérios:

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

    // set the filter.
    resultset.beforeFirst();
    resultset.setFilter(filter);
Techzen
fonte
Eu estava me referindo ao predicado comum, não ao conjunto de resultados relacionado. obrigado
srikanth
0

Somando-se ao que Micheal disse:

Você pode usar Predicate da seguinte maneira na filtragem de coleções em 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;
}

um possível predicado pode ser:

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

Uso:

 final List<DisplayFieldDto> filteredList=
 (List<DisplayFieldDto>)filter(displayFieldsList, filterCriteria);
Jai
fonte
1
Isso basicamente não anula o propósito? A principal razão para escolher uma abordagem funcional é NÃO iterar manualmente e se livrar do for. O nível de abstração se torna mais alto e mais poderoso - no entanto, fazer o for manualmente anula esse propósito e retorna à abstração de baixo nível.
Eugen