2015-06-06 48 views
15

Bir Stream<T> uygulamak istiyorum.Java akışı nasıl uygulanır?

implements Stream<T> kullanmak istemiyorum, çünkü bir ton yöntem uygulamak zorundayım.

Bu önlenebilir mi?

Ben mesela t1, t2 ve t3 akışı nasıl, daha somut olmak gerekirse:

class Foo<T> { 
    T t1, t2, t3; 

    Foo(T t1, T t2, T t3) { 
     this.t1 = t1; 
     this.t2 = t2; 
     this.t3 = t3; 
    } 
} 
+8

'Stream.of (t1 bilmemiz gerekir gibi bulmak zor biraz bulundu , t2, t3). –

+3

['Stream.builder'] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#builder--) – fabian

cevap

24

Stream ait JDK standart uygulaması doğrudan örnekleriz edemez, iç sınıf java.util.stream.ReferencePipeline olduğunu.

yerine varsayılan uygulaması örneğini oluşturmak için java.util.stream.Stream.builder(), java.util.stream.StreamSupport.stream(Spliterator<T>, boolean) ve çeşitli 1, 2 diğer statik fabrika yöntemleri kullanabilirsiniz.

Bir spliterator kullanmak, kaynaklarınızı birden çok parçaya bölünebilirse, etkin bir şekilde paralellik sağlamanıza yardımcı olurken, aynı zamanda nesnel nesneler sağlamanıza olanak tanıdığı için en güçlü yaklaşımdır.

Ayrıca siz de, spliterators geri akışları dönüştürmek özel spliterator koymayı ve kendi durum bilgisi ara işlemleri uygulamak gerekiyorsa o zaman bir akışına geri çevirebiliriz - örneğin Standart API'lardaki eksiklikler nedeniyle - çoğu mevcut ara are not allowed to be stateful.
Örnek için this SO answer adresine bakın. Prensip olarak, akış arayüzünün kendi uygulamanızı yazabilirsiniz, ancak bu oldukça sıkıcı olacaktır.

8

Genellikle kendi akış sınıfınızı yazmanız gerekmez. Bunun yerine mevcut yöntemlerle akış oluşturabilirsiniz. Örneğin, burada, 100 değeri 1 akışı oluşturmak için yapılması gerekenler:

AtomicInteger n = new AtomicInteger(0); 
    Stream<Integer> stream = Stream.generate(() -> n.incrementAndGet()).limit(100); 

yani burada biz tamsayılar sonsuz akışı yarattı: 1, 2, 3, .... o zaman üzerinde limit(100) kullanılan 100 elementin akışını geri almak için sonsuz akış.

Netlik açısından, tam sayılardan oluşan bir akış istiyorsanız (sabit aralıklarla) IntStream.range() kullanmalısınız. Bu, buhar öğelerinin belirlenmesi için keyfi mantığı kullanmanıza izin verdiği için size daha fazla esneklik sağlayan Stream.generate() kullanarak akışların nasıl tanımlanabileceğini göstermek için bir örnektir.

+2

' IntStream.range (0,100) Bu durumda daha verimli olurdu. – the8472

+0

Bu, Stream.generate (n :: incrementAndGet) .limit (100) ' –

+0

için kısaltılabilir. Akışın 0'dan başlamasını istiyorsanız' n :: getAndIncrement' kullanın. –

3

Diğerleri, genel amaçlı bir Stream uygulaması nasıl sağlandığını yanıtladı.

class Foo<T> { 

    T t1, t2, t3; 

    Foo(T t1, T t2, T t3) { 
     this.t1 = t1; 
     this.t2 = t2; 
     this.t3 = t3; 
    } 

    Stream<T> stream() { 
     return Stream.of(t1, t2, t3); 
    } 
} 
6

Eğer özel close() mantığı istiyorum, çünkü kendi Akış yapmak isteyen konum, basit çözüm bir Yineleyiciyi bir Akış oluşturmaktır ve onClose(Runnable) adını veriyoruz belirli gereksinimi ile ilgili olarak, sadece bunu .Örneğin, Jackson üzerinden bir Reader'dan akışı:

MappingIterator<?> values = objectMapper.reader(type).readValues(reader); 
return StreamSupport 
     .stream(Spliterators.spliteratorUnknownSize(values, Spliterator.ORDERED), false) 
     .onClose(() -> { 
      try { 
       reader.close(); 
      } catch (IOException e) { 
       throw new RuntimeException(e); 
      } 
     }); 
1

Bütünlük açısından, doğrudan yanıtlar arasında bu bulamadık burada SO tarih: Bir Akış içine varolan yineleyici dönüştürmek istiyorsanız (Eğer arka arkaya elemanları üretmek istiyorum, çünkü örneğin), bunu kullanın:

StreamSupport.stream(
    Spliterators.spliterator(myIterator, /* initial size*/ 0L, Spliterator.NONNULL), 
    /* not parallel */ false); 

Ben bu StreamSupport, Spliterators ve Spliterator