2015-05-05 23 views
22

Meine Frage kann zu breit sein und wahrscheinlich ist die Antwort ein einfaches NEIN, aber ich muss fragen.Java-Streams in Java 7

Gibt es in Java 7 eine äquivalente Implementierung von (Java 8) streams *?

Ich bin vertraut mit (Java 8) Ströme aber mein Projekt Voraussetzung ist die Verwendung von Java 7.

* Nicht mit inputStream und outputStream verwechselt werden.

+5

Nein, aber Sie können Scala Stream API Blick in die in der JVM läuft, so dass Sie Ihren Code mischen. Vielleicht ist es nicht genau das, wonach Sie suchen, aber es ist einen Versuch wert, falls nötig. –

+0

Ich denke, das ist eine interessante Frage.Sicherlich benötigen Sie eine Java8 JVM bezüglich der syntaktischen Änderungen in der Sprache für Lambda-Ausdrücke. Streams selbst ist ein Konzept, das vom Compiler nicht implementiert wird; aber nach Klassen in Bibliotheken. Es könnte eine sinnlose Aktivität sein, aber Sie möchten vielleicht einfach die Stream-Quellen von Java8 überprüfen; und prüfen, ob sie in einer Java7-Umgebung kompiliert und ausgeführt werden. – GhostCat

+0

@AlexisC. Das ist ein sehr schöner Vorschlag! Vielen Dank! – Athafoud

Antwort

18

In der offiziellen API, Nr.

Es gibt keine öffentlichen Updates für Java 7. Wenn Sie ein Kunde sind, erhalten Sie möglicherweise noch kleinere Updates, aber dies ist nicht (oder sehr, sehr, sehr unwahrscheinlich) für die Back-Portierung der Stream-API.

Mit ein wenig Graben können Sie sich StreamSupport ansehen. Ich habe es nie getestet, aber anscheinend ist es das Ziel, die Stream-API nach Java 6/7 zu portieren, und wenn Sie es mit Lambda-Ausdrücken kombinieren wollen, gibt es auch retrolambda.

Functional Java kann interessant sein. Es ist nicht genau die gleiche Absicht wie die Stream API, aber wenn Ihr Ziel es ist,/etc. eine Liste/ein Array, das Ihren Anforderungen entspricht. Für example:

final List<Integer> b = list(1, 2, 3).map(add.f(-1)); 
listShow(intShow).println(b); // [0, 1, 2] 

Schließlich können Sie die Scala Stream-API suchen. Da Scala auch auf der JVM läuft, können Sie Ihren Code mischen. Vielleicht ist es nicht genau das, wonach Sie suchen, aber es ist einen Versuch wert, falls nötig.

+0

Java 7 kann weiterhin für Produktionsumgebungen verwendet werden - das "Ende des Lebens" ist nur für die kostenlosen Updates. Wenn ein Kunde etwas Unterstützung von Oracle kauft, erhält er immer noch Updates und Bugfixes (sogar für frühere Releases wie Java 6 oder Java 5). Also in diesem Fall ist es in Ordnung, Software mit Ziellaufzeit Java 7 zu entwickeln. – mschenk74

+2

Die Idee, das Java mit Scalla-Code zu mischen, ist sehr interessant. Streamsupport ist auch ein guter Weg zu gehen. – Athafoud

+2

@ mschenk74 Ich habe nicht gesagt, es sollte nicht für Produktionsumgebungen verwendet werden. Sie könnten kleinere Updates erhalten, aber ich möchte darauf hinweisen, dass diese Updates die Stream-API höchst unwahrscheinlich in Java 7, IMO, zurückportieren. –

8

Google Guava Bibliothek einige funktionelle Idiome für Java-Versionen 5 bis 7 enthält:

https://github.com/google/guava/wiki/FunctionalExplained

Außerdem gibt es diese Bibliothek, die Sie vielleicht überprüfen (ich habe nicht davon gehört bis bis einige Minuten vor, wenn ich eine Google-Suche :-) ausgeführt)

http://www.functionaljava.org/

+0

Ich denke "funktional" ist das Zauberwort für die Google-Suche, ich habe es nicht früher gedacht. Ich kannte diese Funktionalität von Guava nicht, aber die Dokumentation sieht gut aus. functionaljava.org sieht etwas unordentlich aus, aber ich werde es versuchen! – Athafoud

2

Eine ist eine andere Wahl hier für Java 6+

Schnittstellen:

interface TransformRule<In, Out> { 
    Out extract(In obj); 
} 

interface FilterRule<T> { 
    boolean apply(T obj); 
} 

Und Java8Stream artigen Container-Klasse für Ansammlung/Karte:

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.HashMap; 
import java.util.Map; 

class FPMapContainer<KeyType, ValueType> extends FPContainer<Map<KeyType, ValueType>, Map.Entry<KeyType, ValueType>, ValueType> { 
    FPMapContainer(Map<KeyType, ValueType> container) { 
     super(container); 
    } 

    @Override 
    public <Out> FPMapContainer<KeyType, Out> map(TransformRule<Map.Entry<KeyType, ValueType>, Out> rule) { 
     return new FPMapContainer<>(handleContainer(getMapMapRule(rule))); 
    } 

    @Override 
    public FPMapContainer<KeyType, ValueType> filter(FilterRule<Map.Entry<KeyType, ValueType>> rule) { 
     return new FPMapContainer<>(handleContainer(getMapFilterRule(rule))); 
    } 

    @Override 
    public FPMapContainer<KeyType, ValueType> concat(Map<KeyType, ValueType> another) { 
     HashMap newOne = new HashMap(container); 
     newOne.putAll(another); 
     return new FPMapContainer<>(newOne); 
    } 

    @Override 
    public FPMapContainer<KeyType, ValueType> concat(FPContainer<Map<KeyType, ValueType>, Map.Entry<KeyType, ValueType>, ValueType> another) { 
     return concat(another.get()); 
    } 

    protected <Out> TransformRule<Map<KeyType, ValueType>, Map<KeyType, Out>> getMapMapRule(final TransformRule<Map.Entry<KeyType, ValueType>, Out> rule) { 
     return new TransformRule<Map<KeyType, ValueType>, Map<KeyType, Out>>() { 
      @Override 
      public Map<KeyType, Out> extract(Map<KeyType, ValueType> obj) { 
       Map<KeyType, Out> newOne = new HashMap<>(); 
       for (Map.Entry<KeyType, ValueType> entry : obj.entrySet()) { 
        newOne.put(entry.getKey(), rule.extract(entry)); 
       } 
       return newOne; 
      } 
     }; 
    } 

    protected TransformRule<Map<KeyType, ValueType>, Map<KeyType, ValueType>> getMapFilterRule(final FilterRule<Map.Entry<KeyType, ValueType>> rule) { 
     return new TransformRule<Map<KeyType, ValueType>, Map<KeyType, ValueType>>() { 
      @Override 
      public Map<KeyType, ValueType> extract(Map<KeyType, ValueType> obj) { 
       Map<KeyType, ValueType> newOne = new HashMap<>(); 
       for (Map.Entry<KeyType, ValueType> entry : obj.entrySet()) { 
        KeyType key = entry.getKey(); 
        ValueType value = entry.getValue(); 
        boolean isValid = rule.apply(entry); 

        if (isValid) { 
         newOne.put(key, value); 
        } 
       } 
       return newOne; 
      } 
     }; 
    } 
} 

class FPCollectionContainer<ValueType> extends FPContainer<Collection<ValueType>, ValueType, ValueType> { 
    FPCollectionContainer(Collection<ValueType> container) { 
     super(container); 
    } 

    @Override 
    public <Out> FPCollectionContainer<Out> map(TransformRule<ValueType, Out> rule) { 
     return new FPCollectionContainer<>(handleContainer(getCollectionMapRule(rule))); 
    } 

    @Override 
    public FPCollectionContainer<ValueType> filter(FilterRule<ValueType> rule) { 
     return new FPCollectionContainer<>(handleContainer(getCollectionFilterRule(rule))); 
    } 

    @Override 
    public FPCollectionContainer<ValueType> concat(Collection<ValueType> another) { 
     ArrayList<ValueType> newOne = new ArrayList<>(container); 
     newOne.addAll(another); 
     return new FPCollectionContainer<>(newOne); 
    } 

    @Override 
    public FPCollectionContainer<ValueType> concat(FPContainer<Collection<ValueType>, ValueType, ValueType> another) { 
     return concat(another.get()); 
    } 

    protected <Out> TransformRule<Collection<ValueType>, Collection<Out>> getCollectionMapRule(final TransformRule<ValueType, Out> rule) { 
     return new TransformRule<Collection<ValueType>, Collection<Out>>() { 
      @Override 
      public Collection<Out> extract(Collection<ValueType> obj) { 
       Collection<Out> newOne = new ArrayList<>(); 
       for (ValueType entry : obj) { 
        newOne.add(rule.extract(entry)); 
       } 
       return newOne; 
      } 
     }; 
    } 

    protected TransformRule<Collection<ValueType>, Collection<ValueType>> getCollectionFilterRule(final FilterRule<ValueType> rule) { 
     return new TransformRule<Collection<ValueType>, Collection<ValueType>>() { 
      @Override 
      public Collection<ValueType> extract(Collection<ValueType> obj) { 
       Collection<ValueType> newOne = new ArrayList<>(); 
       for (ValueType entry : obj) { 
        if (rule.apply(entry)) { 
         newOne.add(entry); 
        } 
       } 
       return newOne; 
      } 
     }; 
    } 
} 

abstract class FPContainer<ContainerTypeWithValueType, ContainerIterableItemType, ValueType> { 

    protected ContainerTypeWithValueType container; 

    protected FPContainer(ContainerTypeWithValueType container) { 
     this.container = container; 
    } 

    public static <KeyType, ValueType> FPMapContainer<KeyType, ValueType> from(Map<KeyType, ValueType> container) { 
     return new FPMapContainer<>(container); 
    } 

    public static <ValueType> FPCollectionContainer<ValueType> from(Collection<ValueType> container) { 
     return new FPCollectionContainer<>(container); 
    } 

    public abstract <Out> Object map(TransformRule<ContainerIterableItemType, Out> rule); 

    public abstract FPContainer<ContainerTypeWithValueType, ContainerIterableItemType, ValueType> filter(FilterRule<ContainerIterableItemType> rule); 

    public abstract FPContainer<ContainerTypeWithValueType, ContainerIterableItemType, ValueType> concat(FPContainer<ContainerTypeWithValueType, ContainerIterableItemType, ValueType> another); 

    public abstract FPContainer<ContainerTypeWithValueType, ContainerIterableItemType, ValueType> concat(ContainerTypeWithValueType another); 

    public <Out> Out reduce(TransformRule<ContainerTypeWithValueType, Out> rule) { 
     return rule.extract(container); 
    } 

    public ContainerTypeWithValueType get() { 
     return container; 
    } 

    protected <ContainerTargetType> ContainerTargetType handleContainer(TransformRule<ContainerTypeWithValueType, ContainerTargetType> collectionMapRule) { 
     if (collectionMapRule != null) { 
      return collectionMapRule.extract(container); 
     } 

     return (ContainerTargetType) container; 
    } 
} 

Jetzt können Sie es verwenden, wie Java8Stream auf diese Weise:

TransformRule<Integer, String> integerStringTransform = new TransformRule<Integer, String>() { 
    @Override 
    public String extract(Integer obj) { 
     return "" + obj; 
    } 
}; 

TransformRule<Collection<String>, String> collectionStringTransform = new TransformRule<Collection<String>, String>() { 
    @Override 
    public String extract(Collection<String> obj) { 
     String result = ""; 
     for (String item : obj) { 
      result += item; 
     } 

     return result; 
    } 
}; 

FilterRule<Integer> ltFourFilter = new FilterRule<Integer>() { 
    @Override 
    public boolean apply(Integer obj) { 
     return obj != null && obj < 4; 
    } 
}; 

// ============================================== 

String reduced; 

// Collection case: 
// `reduced` would be "123" 
reduced = FPContainer.from(Arrays.asList(1, 4)) 
     .concat(FPContainer.from(Arrays.asList(2))) 
     .concat(Arrays.asList(3)) 
     .filter(ltFourFilter) 
     .map(integerStringTransform).reduce(collectionStringTransform); 

// Map case: 
reduced = FPContainer.from(stringIntegerHashMap) 
     .filter(new FilterRule<Map.Entry<String, Integer>>() { 
      @Override 
      public boolean apply(Map.Entry<String, Integer> obj) { 
       return obj.getKey().charAt(0) < 'c' && obj.getValue() < 4; 
      } 
     }) 
     .map(new TransformRule<Map.Entry<String,Integer>, String>() { 
      @Override 
      public String extract(Map.Entry<String, Integer> obj) { 
       return ""+obj.getValue(); 
      } 
     }).reduce(new TransformRule<Map<String, String>, String>() { 
      @Override 
      public String extract(Map<String, String> obj) { 
       String result = ""; 

       Map<String, String> objectStringMap = sortByValue(obj); 
       for (Map.Entry<String, String> entry : objectStringMap.entrySet()) { 
        result += entry.getKey().toString() + entry.getValue(); 
       } 

       return result; 
      } 
     }); 

P.S.

sortByValue (Karte) ist hier ein: (Kredit: https://stackoverflow.com/a/109389/2293635)

public static <K, V> Map<K, V> sortByValue(Map<K, V> map) { 
    List<Map.Entry<K, V>> list = new LinkedList<>(map.entrySet()); 
    Collections.sort(list, new Comparator<Object>() { 
     @SuppressWarnings("unchecked") 
     public int compare(Object o1, Object o2) { 
      return ((Comparable<V>) ((Map.Entry<K, V>) (o1)).getValue()).compareTo(((Map.Entry<K, V>) (o2)).getValue()); 
     } 
    }); 

    Map<K, V> result = new LinkedHashMap<>(); 
    for (Iterator<Map.Entry<K, V>> it = list.iterator(); it.hasNext();) { 
     Map.Entry<K, V> entry = (Map.Entry<K, V>) it.next(); 
     result.put(entry.getKey(), entry.getValue()); 
    } 

    return result; 
}