2016-04-15 9 views
3

私はオブジェクトのリストを持っている単一の引用符で囲まれた単一のプロパティでコンマ区切りの文字列を生成する必要がある。メソッドリファレンスを使用してユーティリティ関数を一般化する方法/ java 8

2例

public String partIDsToString(List<Part> parts){ 
    StringBuilder sb = new StringBuilder(); 
    for(Part part : parts) 
     sb.append("'"+part.getPartNumber() + "',"); 
    return sb.substring(0,sb.length()-1); 
} 

public String companyIDsToString(List<Company> parts){ 
    StringBuilder sb = new StringBuilder(); 
    for(Company c : parts) 
     sb.append("'"+c.getId() + "',"); 
    return sb.substring(0,sb.length()-1); 
} 

私は将来的にこのような複数のメソッドを作成する必要がありますし、この機能を一般化する方法があった場合には思っていた、このような何かを探してイム。

public String objectPropertyToString(List<Object> list, Method getProperty){ 
    StringBuilder sb = new StringBuilder(); 
    for(Object obj: list) 
     sb.append("'"+obj.getProperty() + "',"); 
    return sb.substring(0,sb.length()-1); 
} 

List<Company> companies = getCompaniesList();//not important 
String result = objectPropertyToString(companies , Company::getId); 

List<Part> parts= getPartsList();//not important 
String result = objectPropertyToString(parts, Part::getPartNumber); 

これは、メソッド参照/ lambdas、または他の方法で行うことができますか?

答えて

4

Stream.map()およびCollectors.joining()はあなたの友人です。

companies.stream() 
     .map(Company::getId) 
     .map(s -> "'" + s + "'") 
     .collect(joining(",")); 

あなたはヘルパーメソッドを作成しますが、私の判断で上記のことは価値がないことを十分に簡潔であることができます。

static <T> String mapAndJoin(Collection<T> c, Function<T,String> f){ 
    return c.stream() 
      .map(f) 
      .map(s -> "'" + s + "'") 
      .collect(joining(",")); 
} 

mapAndJoin(companies, Company::getId); 
+0

おかげで、これは私が探していたまさにです。 –

+1

'f :: apply'の使用には意味がありません。 'apply'メソッドが他の' Function'メソッドの 'apply'メソッドを呼び出す新しい' Function'を作成しています。ここで 'f'を使うだけです。 – Holger

+0

Duh、thanks @Holger –

2

this answerに示すように、Collectors.joiningはコンマを生成するために使用することができます区切りリスト。しかし、要素を一重引用符で囲むこともできます。要素を結合する前に、要素ごとに別々のString操作でこれを行うよりも効率的です。次のように

基本的な考え方は次のとおりです。

public static <T> String objectPropertyToString(
        Collection<? extends T> list, Function<T,String> f) { 
    return list.stream().map(f).collect(Collectors.joining("', '", "'", "'")); 
} 

代わりにただ単にカンマで要素を分離するのは、我々はコンマと開い単一引用符に続いて、閉じ単一引用符で区切ります。さらに、最初の要素の前には開始用の一重引用符を使用し、最後の要素の後には一重引用符を付けます。

これはスムーズに機能しますが、1つの例外があります。リストが空白の場合は、最初の開始見積りと末尾の終了見積もりが常に生成されるため、''という結果が得られます。これを解決するために、我々はプロセスに使用StringJoinerに手を得るために、Collectors.joiningが内部で何をたどるために持っているので、私たちは、内蔵のコレクタによって提供されていない方法でそれを設定することができます。基本的に

public static <T> String objectPropertyToString(
        Collection<? extends T> list, Function<T,? extends CharSequence> f) { 
    return list.stream().map(f).collect(
     ()->new StringJoiner("', '", "'", "'").setEmptyValue(""), 
     StringJoiner::add, StringJoiner::merge).toString(); 
} 

この要素が存在しない場合に別の結果を指定するためにsetEmptyValueを使用できるという顕著な例外を伴う以前の試みと同じです。ボーナスとして、ジェネリック型のシグネチャをリラックスできるようになりました。Stringではなく、任意のCharSequenceインスタンスを結合することができます。

使用量が以前のようである:

List<Company> companies = getCompaniesList();//not important 
String result = objectPropertyToString(companies , Company::getId); 

List<Part> parts= getPartsList();//not important 
String result = objectPropertyToString(parts, Part::getPartNumber); 
関連する問題