3
votes

Explication pour v-> v> 5

J'ai un appel de fonction donné et java me donne une erreur car les objets ne sont pas comparables aux ints (bien sûr ...). Quelqu'un peut-il m'expliquer ce que je dois changer?

J'ai essayé d'accolade l'expression lambda différemment mais sans résultat utile. Je pense que l'expression lambda est correcte et que la fonction de filtre est légèrement fausse, mais je ne suis pas en mesure de trouver mon erreur ...

// function call
filter(v -> v > 5)

// function
public Optional<T> filter(Predicate<T> tester) {
    if(isPresent() && tester.test(get())) {
        return this;
    } else {
    return Optional.empty();
    }
}

Je m'attendrais a Optional.empty-Object mais j'obtiens une erreur java car v> 5 Object v n'est pas comparable à un int.


2 commentaires

Il serait bon de regarder également le bloc de code complet. Où utilisez-vous filter et quel est le résultat que vous essayez d'en déduire?


C'est impossible. Vous renvoyez this ce qui signifie que votre classe doit étendre Optional qui est final . Avez-vous votre propre Facultatif ?


4 Réponses :


3
votes

Dans les primitives Java, les types (par exemple int ) et les objets (par exemple Object ) n'ont pas d'ancêtre commun dans la hiérarchie des types. En raison de cela, les prédicats et autres constructions de flux sont disponibles en deux versions, par exemple il y a IntPredicate que vous devez utiliser lorsque vous travaillez avec int et Predicate que vous devez utiliser lorsque vous travaillez avec Object .

Activé la façon d'écrire votre fonction de filtre serait d'utiliser OptionalInt et IntPredicate:

public OptionalInt filter(IntPredicate tester) {
    if (isPresent() && tester.test(get())) {
        return ...
    } else {
        return OptionalInt.empty();
    }
}


5 commentaires

Remarque: Predicate T étend le nombre conviendrait.


@PeterLawrey vous avez absolument raison, la boxe est une autre option.


Existe-t-il un moyen d'y parvenir sans modifier les options et prédicat facultatives dans l'en-tête de la fonction? Parce que je ne veux pas vraiment changer l'en-tête de la fonction.


@PeterLawrey utilisant un filtre public facultatif (testeur de prédicat ) { ne fonctionne malheureusement pas


@Hugugagegi Vous ne pouvez définir que lorsque vous l'avez déclaré le premier tine, éventuellement sur la ligne class Xxxx .



4
votes

Vous devez faire de T une classe wrapper comparable à un int. par exemple

class MyClass {
    public IntOptional filter(IntPredicate test) {

est très bien car v est un int.

Vous ne pouvez pas utiliser cette expression lorsque T est inconnu.

Ce que vous pouvez faire est de supposer que le T doit être un nombre, par exemple

class MyClass<T extends Number> {
    public Optional<T> filter(Predicate<T> test) {

cependant cela produira un ClassCastExpection est T est un autre type.

La vraie solution est de faire de T un Number code >

par exemple

filter( v -> ((Number) v).doubleValue() > 5)

ou en faire un type spécifique comme int

IntStream.range(0, 10)
         .filter(v -> v > 5)
         .forEach(System.out::println);


1 commentaires

La classe est une classe générique. Casting v en Number et utiliser doubleValue () pour le rendre compatible avec Predicate ressemble à un hack . Le problème est à la racine: la déclaration T dans la classe.



2
votes

Je pense que l'expression lambda est correcte et que le la fonction de filtrage est légèrement fausse, mais je ne suis pas en mesure de trouver mon erreur ...

Vous avez raison.
Votre méthode semble vaincre le type générique déclaré pour la classe car tout d'abord votre méthode est définie dans une classe générique.

En supposant que votre classe s'appelle Foo , ici la méthode filter () repose sur le type générique T comme retour / type de paramètre:

public class Foo<T extends Integer>{
     // ...
    public Optional<T> filter(Predicate<T> tester) { 
      // ...
    }
}

Cela fonctionne avec l'inférence.
Vous obtenez ainsi Predicate de T . Mais le T dépend du type générique défini dans la classe et aussi de la manière dont vous avez déclaré l'instance de la classe Foo .
Et il semble qu'ici T n'est pas un Number .

Comme alternative, vous pouvez également vous fier à l'inférence à partir de la variable Foo déclarée.
Si vous faites cela:

Foo<Integer> foo = new Foo<>();
Optional<Integer> optInt = foo.filter(v -> v > 5);

il se compilera correctement car Integer sera déduit de Foo .

Je pense donc que pour résoudre votre problème, vous devez déclarer Number ou Integer comme classe de base du type générique:

public class Foo<T>{
     // ...
    public Optional<T> filter(Predicate<T> tester) { 
      // ...
    }
}

ou vous fier à inférence du client comme dans l'exemple précédent.


0 commentaires

3
votes

v -> v> 5 peut signifier différentes choses. Cela dépend du contexte.

  1. Il peut s'agir d'un (Object v) -> v> 5 provoquant une erreur de compilation car > ne peut pas être appliqué à un objet :

    IntStream.of(123, 123).filter(v -> v > 5);
    
  2. Il peut s'agir d'un (Integer v) -> v> 5 signifiant que le déballage et l'autoboxing seront effectués afin de faire la comparaison et de renvoyer le résultat:

    Stream.<Integer>of(123, 123).filter(v -> v > 5);
    
  3. Il peut s'agir d'un (int v) -> v> 5 signifiant qu'il s'agit d'une instance de IntPredicate et tout se passera bien ici:

    Stream.<Object>of("123", 123).filter(v -> v > 5);
    


0 commentaires