プロパティごとに異なるJava 8


455

Java 8ではStream、各オブジェクトのプロパティの違いをチェックすることにより、API を使用してコレクションをどのようにフィルタリングできますか?

たとえば、Personオブジェクトのリストがあり、同じ名前の人を削除したい場合、

persons.stream().distinct();

Personオブジェクトのデフォルトの等価チェックを使用するため、次のようなものが必要です。

persons.stream().distinct(p -> p.getName());

残念ながら、distinct()メソッドにはそのようなオーバーロードはありません。Personクラス内の等価チェックを変更せずに、これを簡潔に行うことは可能ですか?

回答:


556

ステートフルフィルタdistinctであると考えてください。以下は、以前に表示されたものについての状態を維持する述語を返し、指定された要素が初めて表示されたかどうかを返す関数です。

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}

それからあなたは書くことができます:

persons.stream().filter(distinctByKey(Person::getName))

ストリームが順序付けられて並行して実行されている場合、これにより、最初の要素ではなく、複製の中から任意の要素が保持されることに注意してくださいdistinct()

(これは基本的に、この質問に対する私の回答と同じです:任意のキーに対するJava Lambda Stream Distinct()?


27
互換性を高めるために、引数はそうFunction<? super T, ?>であるべきではないと思いFunction<? super T, Object>ます。また、順序付けされた並列ストリームの場合、このソリューションは(normalとは異なりdistinct())どのオブジェクトが抽出されるかを保証しないことに注意してください。また、シーケンシャルストリームの場合、CHMを使用するとオーバーヘッドが追加されます(@nosidソリューションにはありません)。最後に、このソリューションfilterは、JavaDocで述べられているように、述語がステートレスでなければならないメソッドの規約に違反しています。それでも賛成票を投じた。
Tagir Valeev

3
@java_newbieによって返されるPredicateインスタンスはdistinctByKey、並列ストリーム内で使用されているかどうかはわかりません。並列で使用されている場合はCHMを使用しますが、これは、上記のTagir Valeevが指摘したように、順次の場合のオーバーヘッドを追加します。
スチュアートマークス

5
@holandaGoが返すPredicateインスタンスを保存して再利用すると失敗しますdistinctByKey。ただしdistinctByKey、毎回呼び出すと機能するため、毎回新しいPredicateインスタンスが作成されます。
スチュアートマークス

3
@Chinmayいいえ、それはすべきではありません。使用する場合.filter(distinctByKey(...))。メソッドを1回実行し、述語を返します。したがって、ストリーム内で適切に使用すれば、基本的にマップはすでに再利用されています。マップを静的にすると、マップはすべての用途で共有されます。したがって、thisを使用する2つのストリームがある場合distinctByKey()、両方が同じマップを使用することになりますが、これは望ましいことではありません。
g00glen00b 2017

3
これは非常に賢く、完全に自明ではありません。一般的にこれは、ステートフルラムダであり、根本的CallSiteにリンクされますget$Lambda方法-の新しいインスタンスを返すようPredicateにすべての時間が、これらのインスタンスが同じ共有するmapfunction限り私は理解しています。非常に素晴らしい!
ユージーン

152

別の方法として、名前をキーとして使用してマップに人物を配置することもできます。

persons.collect(Collectors.toMap(Person::getName, p -> p, (p, q) -> p)).values();

名前が重複している場合、保持されているPersonが最初に許可されます。


23
@skiwi:distinct()そのオーバーヘッドなしで実装する方法があると思いますか?実際に目にしたすべての個別の値を覚えていなくても、以前にオブジェクトを見たことがあるかどうか、どのような実装が知るのでしょうか だからのオーバーヘッドtoMapとは、distinct非常に可能性が同じです。
ホルガー2014年

1
@ホルガーオーバーヘッドdistinct()自体が作成することについて考えていなかったので、私はそこで間違っていたかもしれません。
skiwi、

2
そして、明らかにそれはリストの元の順序を台無しにします
Philipp

10
@Philipp:次のように変更することで修正できますpersons.collect(toMap(Person::getName, p -> p, (p, q) -> p, LinkedHashMap::new)).values();
Holger

1
@DanielEarwickerこの質問は「プロパティによって区別」についてです。これを利用するには、ストリームを同じプロパティでソートする必要があります。まず、OPはストリームがソートされているとはまったく述べていませんでした。次に、ストリームは特定のプロパティで並べ替えられているかどうかを検出できません。第3に、提案したことを実行するための本物の「プロパティ別」ストリーム操作はありません。4番目に、実際には、このようなソートされたストリームを取得する方法は2つしかありません。TreeSetいずれにせよ、またはsortedすべての要素もバッファリングするストリーム上ですでに区別されているソート済みソース()。
Holger

101

人物オブジェクトを別のクラスにラップして、人物の名前のみを比較することができます。その後、ラップされたオブジェクトをアンラップして、人物ストリームを再度取得します。ストリーム操作は次のようになります。

persons.stream()
    .map(Wrapper::new)
    .distinct()
    .map(Wrapper::unwrap)
    ...;

クラスWrapperは次のようになります。

class Wrapper {
    private final Person person;
    public Wrapper(Person person) {
        this.person = person;
    }
    public Person unwrap() {
        return person;
    }
    public boolean equals(Object other) {
        if (other instanceof Wrapper) {
            return ((Wrapper) other).person.getName().equals(person.getName());
        } else {
            return false;
        }
    }
    public int hashCode() {
        return person.getName().hashCode();
    }
}


5
@StuartCaieそうではありません...メモはありません。要点はパフォーマンスではなく、既存のAPIへの適応です。
Marko Topolnik、2014年

6
com.google.common.base.Equivalence.wrap(S)とcom.google.common.base.Equivalence.Wrapper.get()も役立ちます。
bjmi 2017年

ラッパークラスをジェネリックにし、キー抽出関数によってパラメーター化することができます。
Lii 2017

equals方法は次のように単純化することができますreturn other instanceof Wrapper && ((Wrapper) other).person.getName().equals(person.getName());
ホルガー

55

を使用した別のソリューションSet。理想的なソリューションではないかもしれませんが、機能します

Set<String> set = new HashSet<>(persons.size());
persons.stream().filter(p -> set.add(p.getName())).collect(Collectors.toList());

または、元のリストを変更できる場合は、removeIfメソッドを使用できます

persons.removeIf(p -> !set.add(p.getName()));

2
これは、サードパーティのライブラリを使用していない場合の最良の回答です。
Manoj Shrestha

5
このセットが指定された要素をまだ含んでいない場合、Set.addがtrueを返すという独創的なアイデアを使用しています。+1
ルビー

この方法はスレッドセーフではないため、並列ストリーム処理では機能しないと思います。
LoBo

@LoBoおそらくそうではありません。これは単なるアイデアであり、単純なケースで機能します。ユーザーはスレッドセーフ/並列処理のためにそれを拡張できます。
サントッシュ

興味深いアプローチですが、別のコレクション(人物)でストリームをフィルタリングしながら外部コレクション(セット)を変更するアンチパターンのように見えます...
Justin Rowe

31

カスタムコンパレーターを備えたTreeSetを使用するより簡単な方法があります。

persons.stream()
    .collect(Collectors.toCollection(
      () -> new TreeSet<Person>((p1, p2) -> p1.getName().compareTo(p2.getName())) 
));

4
あなたの答えは、一意性ではなく順序付けに役立つと思います。しかし、それは私がそれを行う方法について私の考えを設定するのに役立ちました。ここで確認してください:stackoverflow.com/questions/1019854/...を
janagnを

ここで要素を並べ替えると料金が発生します。重複を見つけたり、重複を削除するために並べ替える必要はありません。
pisaruk

12
Comparator.comparing(Person :: getName)
ジャン=フランソワ・Savard

24

RxJava(非常に強力なリアクティブ拡張ライブラリ)を使用することもできます

Observable.from(persons).distinct(Person::getName)

または

Observable.from(persons).distinct(p -> p.getName())

Rxは素晴らしいですが、これは悪い答えです。ObservableプッシュベースStreamですが、プルベースです。stackoverflow.com/questions/30216979/...
sdgfsdh

4
質問は、必ずしもストリームを使用していないjava8ソリューションを求めます。私の答えは、java8ストリームAPIがrx apiよりも少ないことを示しています
frhack

1
reactorを使用すると、次のようになりますFlux.fromIterable(persons).distinct(p -> p.getName())
リテッシュ2017

質問は文字通り「StreamAPIの使用」であり、「必ずしもストリームの使用ではない」と述べています。とはいえ、これはストリームを個別の値にフィルタリングするというXY問題の優れた解決策です。
M.ジャスティン

12

groupingByコレクターを使用できます。

persons.collect(Collectors.groupingBy(p -> p.getName())).values().forEach(t -> System.out.println(t.get(0).getId()));

別のストリームが必要な場合は、これを使用できます。

persons.collect(Collectors.groupingBy(p -> p.getName())).values().stream().map(l -> (l.get(0)));

11

このdistinct(HashingStrategy)方法は、Eclipseコレクションで使用できます。

List<Person> persons = ...;
MutableList<Person> distinct =
    ListIterate.distinct(persons, HashingStrategies.fromFunction(Person::getName));

personsEclipseコレクションインターフェースを実装するようにリファクタリングできる場合は、リストでメソッドを直接呼び出すことができます。

MutableList<Person> persons = ...;
MutableList<Person> distinct =
    persons.distinct(HashingStrategies.fromFunction(Person::getName));

HashingStrategyは、イコールとハッシュコードのカスタム実装を定義できるようにする単純な戦略インターフェースです。

public interface HashingStrategy<E>
{
    int computeHashCode(E object);
    boolean equals(E object1, E object2);
}

注:私はEclipseコレクションのコミッターです。


このソリューションをさらに簡素化できる方法、distinctByがEclipseコレクション9.0に追加されました。 medium.com/@donraab/...
ドナルド・ラーブ

10

できればVavrの使用をお勧めします。このライブラリを使用すると、次のことができます。

io.vavr.collection.List.ofAll(persons)
                       .distinctBy(Person::getName)
                       .toJavaSet() // or any another Java 8 Collection

以前は「javaslang」ライブラリとして知られていました。
user11153

9

StreamExライブラリを使用できます。

StreamEx.of(persons)
        .distinct(Person::getName)
        .toList()

残念ながら、そうでなければ素晴らしいStreamExライブラリのそのメソッドは不十分に設計されています-等しいを使用する代わりにオブジェクトの等価を比較します。これはString、文字列インターンのおかげでsで機能する可能性がありますが、機能しない場合もあります。
トルク

7

Stuart Marksの答えを拡張して、これはより短い方法で、並行マップなしで実行できます(並列ストリームが必要ない場合)。

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    final Set<Object> seen = new HashSet<>();
    return t -> seen.add(keyExtractor.apply(t));
}

次に電話してください:

persons.stream().filter(distinctByKey(p -> p.getName());

2
これは、ストリームが並列である可能性があることを考慮していません。
brunnsbe 16

コメントをありがとう、私は私の答えを更新しました。並列ストリームが必要ない場合は、並行マップを使用しないと、パフォーマンスが大幅に向上します。
WojciechGórski16年

Collections.synchronizedSet(new HashSet<>())代わりにを作成した場合、コードはおそらく並列コレクションで機能します。ただし、を使用する場合よりも遅くなる可能性がありますConcurrentHashMap
Lii 2017

7

Saeed Zarinfamが使用したのと同様のアプローチですが、より多くのJava 8スタイル:)

persons.collect(Collectors.groupingBy(p -> p.getName())).values().stream()
 .map(plans -> plans.stream().findFirst().get())
 .collect(toList());

1
私は、マップのラインを交換するだろうflatMap(plans -> plans.stream().findFirst().stream())、それはオプションでgetの使用を避ける
アンドリューSneck

多分これも大丈夫です:flatMap(plans-> plans.stream()。limit(1))
Rrr

6

私は一般的なバージョンを作りました:

private <T, R> Collector<T, ?, Stream<T>> distinctByKey(Function<T, R> keyExtractor) {
    return Collectors.collectingAndThen(
            toMap(
                    keyExtractor,
                    t -> t,
                    (t1, t2) -> t1
            ),
            (Map<R, T> map) -> map.values().stream()
    );
}

例:

Stream.of(new Person("Jean"), 
          new Person("Jean"),
          new Person("Paul")
)
    .filter(...)
    .collect(distinctByKey(Person::getName)) // return a stream of Person with 2 elements, jean and Paul
    .map(...)
    .collect(toList())



5

これに対する私のアプローチは、同じプロパティを持つすべてのオブジェクトを一緒にグループ化し、グループを1のサイズに切り詰め、最後にそれらをとして収集することListです。

  List<YourPersonClass> listWithDistinctPersons =   persons.stream()
            //operators to remove duplicates based on person name
            .collect(Collectors.groupingBy(p -> p.getName()))
            .values()
            .stream()
            //cut short the groups to size of 1
            .flatMap(group -> group.stream().limit(1))
            //collect distinct users as list
            .collect(Collectors.toList());

3

個別のオブジェクトリストは、次を使用して見つけることができます。

 List distinctPersons = persons.stream()
                    .collect(Collectors.collectingAndThen(
                            Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person:: getName))),
                            ArrayList::new));

2

これを実装する最も簡単な方法はComparator、要素のプロパティを使用して作成できるオプションをすでに提供しているため、ソート機能にジャンプすることです。次に、重複を除外する必要がPredicateあります。これは、並べ替えられたストリームのすべての等しい要素が隣接しているという事実を使用するstatefull を使用して実行できます。

Comparator<Person> c=Comparator.comparing(Person::getName);
stream.sorted(c).filter(new Predicate<Person>() {
    Person previous;
    public boolean test(Person p) {
      if(previous!=null && c.compare(previous, p)==0)
        return false;
      previous=p;
      return true;
    }
})./* more stream operations here */;

もちろん、statefull Predicateはスレッドセーフではありませんが、それが必要な場合は、このロジックをaに移動してCollector、ストリームをスレッドセーフに処理させることができますCollector。これは、質問で教えていない個別の要素のストリームをどのように処理するかによって異なります。


1

@josketresの答えに基づいて、汎用的なユーティリティメソッドを作成しました。

Collectorを作成することで、これをよりJava 8対応にすることができます。

public static <T> Set<T> removeDuplicates(Collection<T> input, Comparator<T> comparer) {
    return input.stream()
            .collect(toCollection(() -> new TreeSet<>(comparer)));
}


@Test
public void removeDuplicatesWithDuplicates() {
    ArrayList<C> input = new ArrayList<>();
    Collections.addAll(input, new C(7), new C(42), new C(42));
    Collection<C> result = removeDuplicates(input, (c1, c2) -> Integer.compare(c1.value, c2.value));
    assertEquals(2, result.size());
    assertTrue(result.stream().anyMatch(c -> c.value == 7));
    assertTrue(result.stream().anyMatch(c -> c.value == 42));
}

@Test
public void removeDuplicatesWithoutDuplicates() {
    ArrayList<C> input = new ArrayList<>();
    Collections.addAll(input, new C(1), new C(2), new C(3));
    Collection<C> result = removeDuplicates(input, (t1, t2) -> Integer.compare(t1.value, t2.value));
    assertEquals(3, result.size());
    assertTrue(result.stream().anyMatch(c -> c.value == 1));
    assertTrue(result.stream().anyMatch(c -> c.value == 2));
    assertTrue(result.stream().anyMatch(c -> c.value == 3));
}

private class C {
    public final int value;

    private C(int value) {
        this.value = value;
    }
}

1

多分誰かのために役立つでしょう。もう1つ要件がありました。Aサードパーティからのオブジェクトのリストを持つことで、同じA.bフィールドが同じであるすべてを削除しますA.id(リスト内にA同じオブジェクトが複数あるA.id)。Tagir Valeevによるストリームパーティションの回答は、カスタムを使用してリターンするように促しました。あとはSimple が行います。CollectorMap<A.id, List<A>>flatMap

 public static <T, K, K2> Collector<T, ?, Map<K, List<T>>> groupingDistinctBy(Function<T, K> keyFunction, Function<T, K2> distinctFunction) {
    return groupingBy(keyFunction, Collector.of((Supplier<Map<K2, T>>) HashMap::new,
            (map, error) -> map.putIfAbsent(distinctFunction.apply(error), error),
            (left, right) -> {
                left.putAll(right);
                return left;
            }, map -> new ArrayList<>(map.values()),
            Collector.Characteristics.UNORDERED)); }

1

2つのキーに基づいてリストから個別の要素を取得することを想定していた状況がありました。2つのキーに基づいて区別したい場合、またはキーを合成する場合は、これを試してください

class Person{
    int rollno;
    String name;
}
List<Person> personList;


Function<Person, List<Object>> compositeKey = personList->
        Arrays.<Object>asList(personList.getName(), personList.getRollno());

Map<Object, List<Person>> map = personList.stream().collect(Collectors.groupingBy(compositeKey, Collectors.toList()));

List<Object> duplicateEntrys = map.entrySet().stream()`enter code here`
        .filter(settingMap ->
                settingMap.getValue().size() > 1)
        .collect(Collectors.toList());

0

私の場合、前の要素を制御する必要がありました。次に、前の要素が現在の要素と異なるかどうかを制御するステートフルな述語を作成しました。その場合は保持しました。

public List<Log> fetchLogById(Long id) {
    return this.findLogById(id).stream()
        .filter(new LogPredicate())
        .collect(Collectors.toList());
}

public class LogPredicate implements Predicate<Log> {

    private Log previous;

    public boolean test(Log atual) {
        boolean isDifferent = previouws == null || verifyIfDifferentLog(current, previous);

        if (isDifferent) {
            previous = current;
        }
        return isDifferent;
    }

    private boolean verifyIfDifferentLog(Log current, Log previous) {
        return !current.getId().equals(previous.getId());
    }

}

0

このリストの私のソリューション:

List<HolderEntry> result ....

List<HolderEntry> dto3s = new ArrayList<>(result.stream().collect(toMap(
            HolderEntry::getId,
            holder -> holder,  //or Function.identity() if you want
            (holder1, holder2) -> holder1 
    )).values());

私の状況では、明確な値を見つけてそれらをリストに入れたいと思います。


0

最高の回答はJava 8に対する絶対的な最良の回答ですが、同時にパフォーマンスの面で絶対的に最悪です。パフォーマンスの悪いアプリケーションが本当に必要な場合は、先に進んでそれを使用してください。個人名の一意のセットを抽出するという単純な要件は、単なる「For-Each」と「セット」によって達成されるものとします。リストのサイズが10を超えると、事態はさらに悪化します。

次のように、20個のオブジェクトのコレクションがあるとします。

public static final List<SimpleEvent> testList = Arrays.asList(
            new SimpleEvent("Tom"), new SimpleEvent("Dick"),new SimpleEvent("Harry"),new SimpleEvent("Tom"),
            new SimpleEvent("Dick"),new SimpleEvent("Huckle"),new SimpleEvent("Berry"),new SimpleEvent("Tom"),
            new SimpleEvent("Dick"),new SimpleEvent("Moses"),new SimpleEvent("Chiku"),new SimpleEvent("Cherry"),
            new SimpleEvent("Roses"),new SimpleEvent("Moses"),new SimpleEvent("Chiku"),new SimpleEvent("gotya"),
            new SimpleEvent("Gotye"),new SimpleEvent("Nibble"),new SimpleEvent("Berry"),new SimpleEvent("Jibble"));

オブジェクトの場所はSimpleEvent次のようになります。

public class SimpleEvent {

private String name;
private String type;

public SimpleEvent(String name) {
    this.name = name;
    this.type = "type_"+name;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}
}

テストするには、次のようなJMHコードを使用します(承認された回答で言及されているのと同じ別個の ByKey述語を使用していることに注意してください)

@Benchmark
@OutputTimeUnit(TimeUnit.SECONDS)
public void aStreamBasedUniqueSet(Blackhole blackhole) throws Exception{

    Set<String> uniqueNames = testList
            .stream()
            .filter(distinctByKey(SimpleEvent::getName))
            .map(SimpleEvent::getName)
            .collect(Collectors.toSet());
    blackhole.consume(uniqueNames);
}

@Benchmark
@OutputTimeUnit(TimeUnit.SECONDS)
public void aForEachBasedUniqueSet(Blackhole blackhole) throws Exception{
    Set<String> uniqueNames = new HashSet<>();

    for (SimpleEvent event : testList) {
        uniqueNames.add(event.getName());
    }
    blackhole.consume(uniqueNames);
}

public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
            .include(MyBenchmark.class.getSimpleName())
            .forks(1)
            .mode(Mode.Throughput)
            .warmupBatchSize(3)
            .warmupIterations(3)
            .measurementIterations(3)
            .build();

    new Runner(opt).run();
}

次に、次のようなベンチマーク結果が得られます。

Benchmark                                  Mode  Samples        Score  Score error  Units
c.s.MyBenchmark.aForEachBasedUniqueSet    thrpt        3  2635199.952  1663320.718  ops/s
c.s.MyBenchmark.aStreamBasedUniqueSet     thrpt        3   729134.695   895825.697  ops/s

ご覧のとおり、単純なFor-Eachは、Java 8 Streamと比較して、スループットが3倍、エラースコアが低くなっています。

より高いスループット、より良いパフォーマンス


1
おかげで、質問はストリームAPIのコンテキストで非常に具体的でした
RichK

はい、私は同意します。「最高の回答はJava 8に対する絶対的な最良の回答です」とすでに述べました。問題はn通りの方法で解決できますが、ここで強調しているのは、パフォーマンスの低下が危険であるJava 8 Streamsでは危険ではなく、簡単に問題を解決できることです。:)
Abhinav Ganguly

0
Here is the example
public class PayRoll {

    private int payRollId;
    private int id;
    private String name;
    private String dept;
    private int salary;


    public PayRoll(int payRollId, int id, String name, String dept, int salary) {
        super();
        this.payRollId = payRollId;
        this.id = id;
        this.name = name;
        this.dept = dept;
        this.salary = salary;
    }
} 

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collector;
import java.util.stream.Collectors;

public class Prac {
    public static void main(String[] args) {

        int salary=70000;
        PayRoll payRoll=new PayRoll(1311, 1, "A", "HR", salary);
        PayRoll payRoll2=new PayRoll(1411, 2    , "B", "Technical", salary);
        PayRoll payRoll3=new PayRoll(1511, 1, "C", "HR", salary);
        PayRoll payRoll4=new PayRoll(1611, 1, "D", "Technical", salary);
        PayRoll payRoll5=new PayRoll(711, 3,"E", "Technical", salary);
        PayRoll payRoll6=new PayRoll(1811, 3, "F", "Technical", salary);
        List<PayRoll>list=new ArrayList<PayRoll>();
        list.add(payRoll);
        list.add(payRoll2);
        list.add(payRoll3);
        list.add(payRoll4);
        list.add(payRoll5);
        list.add(payRoll6);


        Map<Object, Optional<PayRoll>> k = list.stream().collect(Collectors.groupingBy(p->p.getId()+"|"+p.getDept(),Collectors.maxBy(Comparator.comparingInt(PayRoll::getPayRollId))));


        k.entrySet().forEach(p->
        {
            if(p.getValue().isPresent())
            {
                System.out.println(p.getValue().get());
            }
        });



    }
}

Output:

PayRoll [payRollId=1611, id=1, name=D, dept=Technical, salary=70000]
PayRoll [payRollId=1811, id=3, name=F, dept=Technical, salary=70000]
PayRoll [payRollId=1411, id=2, name=B, dept=Technical, salary=70000]
PayRoll [payRollId=1511, id=1, name=C, dept=HR, salary=70000]

-2

あなたが人のリストにしたいなら、以下は簡単な方法でしょう

Set<String> set = new HashSet<>(persons.size());
persons.stream().filter(p -> set.add(p.getName())).collect(Collectors.toList());

あなたは明確なまたはユニーク検索したい場合はさらに、名前のリストいない人を、あなたはよくとして次の二つの方法を使用して行うことができます。

方法1:使用 distinct

persons.stream().map(x->x.getName()).distinct.collect(Collectors.toList());

方法2:使用 HashSet

Set<E> set = new HashSet<>();
set.addAll(person.stream().map(x->x.getName()).collect(Collectors.toList()));

2
これにより、Persons ではなく名前のリストが生成されます。
ハルク、

1
これはまさに私が探していたものです。コレクションを相互に変換するときに重複を排除するために、1行のメソッドが必要でした。ありがとう。
Raj

-3

あなたが書くことができる最も単純なコード:

    persons.stream().map(x-> x.getName()).distinct().collect(Collectors.toList());

12
ただし、Persons by nameではなく、名前の明確なリストが表示されます
RichK
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.