2017-06-15 13 views
2

N個のマルチキャストソケットを開く必要があります(Nは引数リストのサイズになります)。私はループ内の各Nソケットに同じデータを送り、最後に各ソケットを閉じます。私の質問は、try-with-resourcesブロックを使ってこれをどうやってやるのでしょうか?以下は、私は単一のリソースでこれを行うだろうかです:Java試行リソース不明リソース数

final int port = ...; 
try (final MulticastSocket socket = new MulticastSocket(port)) { 
    // Do a bunch of sends of small packet data over a long period of time 
    ... 
} 

私は複数のポートでこれを行うに考えることができる唯一の方法は以下の通りです:

final List<Integer> ports = ...; 
final List<MulticastSocket> sockets = new ArrayList<>(ports.size()); 
try { 
    for (final Integer port : ports) { 
     sockets.add(new MulticastSocket(port)); 
    } 

    // Do a bunch of sends of small packet data over a long period of time 
    ... 
} finally { 
    for (final MulticastSocket socket : sockets) { 
     try { 
      socket.close(); 
     } catch (final Throwable t) { 
      // Eat the exception 
     } 
    } 
} 

は、より簡潔な方法はありますこれを達成するために、または私の提案された解決策は、それが得られるほど良いですか?

答えて

0

、私は次のクラスを思い付いた...

package myNamespace; 

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.Iterator; 
import java.util.List; 
import java.util.ListIterator; 

import myNamespace.ThrowingFunction; 
import myNamespace.ThrowingSupplier; 

/** Collection of AutoCloseable objects */ 
public class ResourceCollection<T extends AutoCloseable> 
     implements Iterable<T>, AutoCloseable { 

    /** Resources owned by this instance */ 
    private final List<T> myResources; 

    /** 
    * Constructor 
    * @param allocator Function used to allocate each resource 
    * @param count  Number of times to call the allocator 
    * @throws E Thrown if any of the allocators throw 
    */ 
    public <E extends Throwable> ResourceCollection(
      final ThrowingSupplier<T, E> allocator, final int count) 
      throws E { 
     myResources = new ArrayList<>(count); 
     try { 
      while (myResources.size() < count) { 
       final T resource = allocator.getThrows(); 
       myResources.add(resource); 
      } 
     } catch (final Throwable e) { 
      close(); 
      throw e; 
     } 
    } 

    /** 
    * Constructor 
    * @param allocator Function used to allocate each resource 
    * @param input  List of input parameters passed to the allocator 
    * @throws E Thrown if any of the allocators throw 
    */ 
    public <U, E extends Throwable> ResourceCollection(
      final ThrowingFunction<U, T, E> allocator, final Collection<U> input) 
      throws E { 
     myResources = new ArrayList<>(input.size()); 
     try { 
      for (final U value : input) { 
       final T resource = allocator.applyThrows(value); 
       myResources.add(resource); 
      } 
     } catch (final Throwable e) { 
      close(); 
      throw e; 
     } 
    } 

    /** 
    * Gets the number of resources in the collection 
    * @return The number of resources in the collection 
    */ 
    public int size() { 
     return myResources.size(); 
    } 

    /** 
    * Gets whether the collection contains no resources 
    * @return Whether the collection contains no resources 
    */ 
    public boolean isEmpty() { 
     return myResources.isEmpty(); 
    } 

    /** 
    * Gets the resource at index i 
    * @param i The index of a resource, in the range [0, size()) 
    * @return The resource at index i 
    */ 
    public T get(final int i) { 
     return myResources.get(i); 
    } 

    @Override 
    public Iterator<T> iterator() { 
     return myResources.iterator(); 
    } 

    @Override 
    public void close() { 
     final ListIterator<T> resourceIter = 
       myResources.listIterator(myResources.size()); 
     while (resourceIter.hasPrevious()) { 
      final T resource = resourceIter.previous(); 
      if (resource != null) { 
       try { 
        resource .close(); 
        resourceIter.remove(); 
       } catch (final Throwable t) { 
        // Eat the exception 
       } 
      } 
     } 
    } 

} 
1

あなたがやっていることは、それが得られるほど実用的です。

あなたは、List<AutoCloseable>が含まれており、コンストラクタパラメータとしてcloseablesの数と各閉鎖可能を作成するために呼び出すための工場を受け入れる多近いAutoCloseable汎用を作成し、そのclose()が呼び出されたときに、それらすべてを閉じることができこのように使用することができます:

...しかし、それはおそらく過剰です。

+0

ラムダ式で 'port'は何ですか? – saka1029

+0

@ saka1029ああ、そこにそれを修正しました。しかし、それはポイントではありません。ポイントは構造物です。詳細は学生に練習として残されます。 –

2

は、try-と資源の保証を維持するために再帰的にそれを実行します。

void foo(List<Integer> ports, List<Socket> sockets) { 
    if (sockets.size() == ports.size()) { 
    // Do something with your sockets. 
    } else { 
    try (Socket s = new MulticastSocket(ports.get(sockets.size())) { 
     sockets.add(s); 
     foo(ports, sockets); 
     // You could call sockets.remove(sockets.size()-1) here. 
     // Not convinced whether it's worth it. 
    } 
    } 
} 
+0

ループすることはできませんが、再帰呼び出しを作成することはできますか?これは本当に素晴らしいです – Eugene

+0

私はあなたが何をやっていたのか理解するためにこれを2度読んでいた。 +1は創造性と簡潔さのためですが、私はまだMikeの提案ではなく、代わりにユーティリティ 'AutoCloseable'クラスを作成することをお勧めします。それはより読みやすく、これを酷使する再帰がちょっと感じます...汚いです。 –

+0

@JeffGあなたが快適に感じることをする必要があります。最終的にはそれを維持する必要があるからです。このようなことなしに、複数のTWRブロックの正確に同等のセマンティクスを実装するのはかなり面倒で困難です。 –

0

MulticastSocketインスタンスを格納するためにArrayListを使用するためのポイントは何ですか?

あなたはそれを言った:私は、その後 ループ内でN個のソケットのそれぞれに同じデータを送信し、最終的には、各ソケットを閉じます

これをループで作成し、繰り返し処理ごとに同じ処理を送信できます。
これを行うには、デザインを少し変更する必要があります。
MulticastSocketの処理タスクは、使用するポートも指定できる機能インターフェイスによって実行できます。例えば

:あなたが処理を適用するには、パラメータとして、この機能インタフェースを取る方法かもしれない

@FunctionalInterface 
public interface SocketProcessor { 
    void process(MulticastSocket multicastSocket) ; 
} 

:クライアントコードから最後に

public static void processSocket(SocketProcessor socketProcessor, Integer port) throws IOException { 
    try (final MulticastSocket socket = new MulticastSocket(port)) { 
    socketProcessor.process(socket); 
    } 
} 

を、あなたが作成することができますラムダを持つsocketProcessorインスタンス:

SocketProcessor socketProcessor = (MulticastSocket socket) -> { 
    socket.send(...); 
    socket.send(...); 
}; 

そして、作成したばかりの、適切なポートとSocketProcessorインスタンスでprocessSocketを呼び出すためのポート上のあなたはできるループ:

for (final Integer port : ports) { 
    try { 
     processSocket(socketProcessor, port); 
    } catch (IOException e) { 
     // do processing 
    } 
} 

このソリューションは、(本当に長いことなく)短い必要はありませんが、それは本当に明確です。
二つの主な懸念を分離し:

    processSocket(SocketProcessor)
  • 具体的なタスクを定義するボイラープレートコード

  • SocketProcessorを実行します。

    マイクNakisによって提案されたアイデアに触発さ
+0

あなたの答えは、パケットをインターリーブして送信する必要があることを忘れてしまったことに気づきました(たとえば、すべてのソケットでパケット1を送信し、次にすべてのソケットでパケット2を送信するなど)。それは私の要件(私の質問には間違いなく欠けている)の一つであることを考えると、この答えは、送信する必要のある各パケットのための新しいソケットを作成する必要があります。 –

+0

@Jeff Gこの場合、実際に提案された回答はあなたのニーズに合っていません。 – davidxxx

関連する問題