Java 8 notes d'étude de flux

Flux tapez le chemin complet est: java.util.stream.Stream

Comme un atout majeur de Java 8, il package java.io de InputStream et OutputStream sont des concepts complètement différents. Il est également différent Stax pour analyser XML Stream, flux Amazon Kinesis est pas le traitement en temps réel de grandes quantités de données. Flux 8 Java est renforcée dans la collection (Collection) la fonction d'objet, il se concentre sur la collecte de divers objets est une opération de polymérisation très pratique et efficace (fonctionnement global) ou des opérations de données de masse ( en vrac d'exploitation de données). Lambda API flux au moyen de la même émergents, ce qui améliore considérablement l'efficacité de la programmation et la lisibilité du programme. En même temps , il fournit en série et en parallèle des modes à agréger le fonctionnement, le modèle peut concurrency tirer parti des processeurs multi-core, avec fork / join et tâche fractionnée en parallèle pour accélérer le processus. Habituellement écrire du code parallèle est difficile et, mais en utilisant l' API Stream risque d' erreur sans écrire une seule ligne de code multi-thread, vous pouvez facilement écrire des programmes concurrents de haute performance. Ainsi, java.util.stream en Java 8 pour la première fois est un produit des effets combinés d'une langue fonctionnelle + ère multi-core.

Stream n'est pas une collection d'éléments, il n'est pas une structure de données des données ne sont pas enregistrées, il est sur les algorithmes et calculs, il est plus comme une version avancée de Iterator. La version originale du Iterator, un utilisateur peut explicitement par les éléments et effectuer une certaine opération, version Advanced Stream, aussi longtemps que les besoins de l'utilisateur d'effectuer une opération donnée de ses éléments contenus, tels que « filtrent plus de longueur de 10 string « » Obtenir la première lettre de chaque chaîne « et, implicitement flux traversèrent la conversion interne des données en conséquence.

Comme un flux iterator (Iterator), unidirectionnel, pas alternatif, les données ne peuvent être traversèrent une fois traversé une fois après épuisé, comme l'eau coule de l'avant, disparu.

Et tandis que l'itérateur est différent et, en parallèle opération Stream, seulement itérateurs impératif, l'opération de sérialisation. Comme son nom l'indique, lorsqu'un mode série à parcourir, puis lire chaque article à lire l'article suivant. Lorsqu'elles sont utilisées pour parcourir les données parallèles est divisée en une pluralité de segments, chacun d'eux étant traité dans un filetage différent, puis délivre en sortie les résultats ensemble. parallélisme dépendant Fork flux introduit dans le cadre java7 / join (JSR166y) pour accélérer la tâche de processus et divisé. Parallel Java API évolution est essentiellement comme suit:

  1. 1,0-1,4 dans java.lang.Thread
  2. 5.0 java.util.concurrent
  3. 6.0 phaseurs, etc.
  4. La fourchette 7,0 / cadre Inscrivez-vous
  5. 8,0 Lambda

Stream est une autre caractéristique importante est la source de données elle-même peut être infini (?)

configuration flux

Lorsque nous utilisons un flux de temps, en général se compose de trois étapes de base:

Obtient une source de données (source) → → effectuer l'opération de conversion de données pour obtenir les résultats souhaités, chaque conversion ne change pas l'objet de flux d'origine et retourne un nouvel objet Stream (il peut y avoir plusieurs conversions), ce qui peut permettre son fonctionnement même que l'agencement de chaîne, dans un conduit, tel que représenté sur la Fig.

1. La configuration du conduit d'écoulement figure (courant Pipeline)

Il y a plusieurs façons de générer des flux Source:

  • De la collection et les tableaux
    • Collection.stream ()
    • Collection.parallelStream ()
    • Arrays.stream (array T) ou Stream.of ()

    从 BufferedReader

    • java.io.BufferedReader.lines ()
  • usine statique
  • java.util.stream.IntStream.range ()
  • java.nio.file.Files.walk ()
  • construire vous-même
    • java.util.Spliterator

    autres

    • Random.ints ()
    • BitSet.stream ()
    • Pattern.splitAsStream (java.lang.CharSequence)
    • JarFile.stream ()

Type d'opération est divisé en deux courants:

  • Intermédiaire : un courant peut être suivie par zéro ou plusieurs opérations intermédiaires. Son but principal est d'ouvrir le flux, ce qui rend un certain degré de mappage des données / filtrage, puis retourne un nouveau flux, à utiliser la prochaine opération. De telles opérations sont d'un inerte (le paresseux), qui est, seuls les appels à ces méthodes, et ne démarre pas vraiment traverse flux.
  • Terminal : un flux ne peut avoir qu'une seule opération terminal, lorsque l'opération est effectuée, le débit serait utilisé « léger », et ne peut plus être utilisé. Donc , ce doit être le dernier flux d'opération. La mise en œuvre des opérations de terminal va vraiment commencer à traverser le cours d' eau et produit un résultat ou un effet secondaire.

Dans l'opération de commutation une pluralité de fois (opération intermédiaire) pour un flux, le flux chaque élément de chaque conversion, et est exécuté de manière répétée, de sorte que la complexité de temps est N (conversion) pour la boucle lorsque toutes les opérations sont ne résumer en sortir? En fait, pas le cas, les opérations de conversion sont paresseux et intégreront opération de conversion multiple lorsque le fonctionnement du terminal, une fois que le cycle est terminé. Nous pouvons comprendre un tel simple, Stream, il y a un ensemble de fonctions opérationnelles, chaque opération de conversion est de convertir la fonction dans cette collection, le cycle de collecte correspondant flux en fonctionnement du terminal, puis exécuter toutes les fonctions de chaque élément .

Une autre opération est appelée  court-circuit . Utilisé pour se référer à:

  • Pour une opération intermédiaire, si l'on admet qu'un infini (infini / non borné) Stream, mais renvoie un nouveau flux limité.
  • Pour une opération de terminal, si elle est d'accepter un flux infini, mais le résultat peut être calculé pour un temps limité.

Lors de l'utilisation d'un flux infini, et je souhaite terminer l'opération dans un temps limité, vous avez une opération de court-circuit dans le pipeline est une condition nécessaire mais non suffisante.

3. Une liste d'exemple de fonctionnement du courant

courant () Obtient la source de petits articles en cours, le filtre et le fonctionnement intermédiaire est mapToInt, les données de filtrage et de conversion, une somme finale () de la borne de commande, pour répondre aux exigences relatives au poids de tous les petits éléments additionnés.

flux d'emploi détaillé

Autrement dit, l'utilisation du flux est de mettre en oeuvre un filtre-map-réduire le processus pour produire un résultat final ou de provoquer un effet secondaire (effet secondaire).

usage spécifique

1. Créez un flux commun

1.1 Méthode de collecte sous flux () et parallelStream ()

List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

1.2 Les tableaux en mode courant (), le flux dans le réseau à un

Integer[] nums = new Integer[10];
Stream<Integer> stream = Arrays.stream(nums);

1.3 Flux de méthode statique: de (), générer iterate () ()

Stream<Integer> stream1 = Stream.of(1,2,3,4,5);
/**
* iterate第一个参数是种子,第二个参数为元素值的生成过程,也就是
* 除第一个位置(0位置)之后的元素值都由前一个元素值作为输入参数(x),
* limit是限制Stream长度
*/
Stream<Integer> stream2 = Stream.iterate(0, x -> x + 2).limit(6);
stream2.forEach(System.out::println);//0 2 4 6 8 10
		
Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
stream3.forEach(System.out::println);//0.4196684476746345 0.9268584030269439

Procédé 1,4 BufferedReader.lines (), chaque contenu de la ligne à un flux

BufferedReader reader = new BufferedReader(new FileReader("F:\\test_stream.txt"));
Stream<String> lineStream = reader.lines();
lineStream.forEach(System.out::println);

1.5 Utilisation procédé Pattern.splitAsStream (), les cordes sont séparés en flux

Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
stringStream.forEach(System.out::println);

2. Le fonctionnement du flot intermédiaire

2.1 Criblage de la tranche
        filtre: Filtre à certains éléments de flux
        limite (n): obtenir n éléments de
        saut (n): n sauter élément, à la limite (n) peut être mis en oeuvre onglet
        distinct: dans le flux élémentaire par hashCode () élément et equals () déduplication

Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);
 
Stream<Integer> newStream = stream.filter(s -> s > 5) //6 6 7 9 8 10 12 14 14
        .distinct() //6 7 9 8 10 12 14
        .skip(2) //9 8 10 12 14
        .limit(2); //9 8
newStream.forEach(System.out::println);

2.2 Cartographie        
        carte: réception d' une fonction en tant que paramètre, la fonction sera appliquée à chaque élément, et des cartes dans un nouvel élément.
        flatMap: la réception d' une fonction en tant que paramètre, la valeur de chaque flux sont remplacés par un autre flux, alors les flux de tous connectés à un flux.

List<String> list = Arrays.asList("a,b,c", "1,2,3");
 
//将每个元素转成一个新的且不带逗号的元素
Stream<String> s1 = list.stream().map(s -> s.replaceAll(",", ""));
s1.forEach(System.out::println); // abc  123
 
Stream<String> s3 = list.stream().flatMap(s -> {
    //将每个元素转换成一个stream
    String[] split = s.split(",");
    Stream<String> s2 = Arrays.stream(split);
    return s2;
});
s3.forEach(System.out::println); // a b c 1 2 3

2.3 Tri
        trié (): ordre naturel, le flux à atteindre par les éléments d' interface Comparable
        triée (com Comparator): commande de commande personnalisé Séquenceur Comparator  

List<String> list = Arrays.asList("aa", "ff", "dd");
//String 类自身已实现Compareable接口
list.stream().sorted().forEach(System.out::println);// aa dd ff
 
Student s1 = new Student("aa", 10);
Student s2 = new Student("bb", 20);
Student s3 = new Student("aa", 30);
Student s4 = new Student("dd", 40);
List<Student> studentList = Arrays.asList(s1, s2, s3, s4);
 
//自定义排序:先按姓名升序,姓名相同则按年龄升序
studentList.stream().sorted(
        (o1, o2) -> {
            if (o1.getName().equals(o2.getName())) {
                return o1.getAge() - o2.getAge();
            } else {
                return o1.getName().compareTo(o2.getName());
            }
        }
).forEach(System.out::println);

2.4 Consommation
        coup d' oeil: Comme sur la carte, peuvent être obtenus dans chaque flux élémentaire. Cependant, une carte est reçu l' expression de la fonction, la valeur de retour, le coup d' oeil d'expression des consommateurs est reçue, il n'y a pas de valeur de retour.

Student s1 = new Student("aa", 10);
Student s2 = new Student("bb", 20);
List<Student> studentList = Arrays.asList(s1, s2);
 
studentList.stream()
        .peek(o -> o.setAge(100))
        .forEach(System.out::println);   
 
//结果:
Student{name='aa', age=100}
Student{name='bb', age=100}            

Résumé: coup d'oeil sans recevoir une valeur de retour expression lambda peut faire une sortie, un traitement externe. recevoir une carte avec une valeur de retour d'expression lambda, après type générique de flux carte de paramètres pour convertir le type des rendements d'expression lambda.

3. terminaison flux d'opération

3.1 matchs opération de polymérisation
        allMatch: réception d' un retour de la fonction prédicats true si le flux lorsque chaque élément correspond à l'affirmation, sinon false
        lors de la réception d' une fonction prédicats, chaque élément lorsque le flux ne se conforme pas à l'affirmation: noneMatch renvoie true, sinon retourne false
        AnyMatch: réception d' une fonction de prédicat, aussi longtemps qu'il y a un flux satisfaisant aux rendements d'éléments d'assertion vrai, sinon retourne false
        la findFirst: un premier élément de courant de retour
        findAny: tout flux élémentaire dans le retour
        comptage: flux de retour le nombre total d'éléments
        max: valeur maximum des éléments dans le flux de retour
        min: l' élément de retour de flux minimum

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
 
boolean allMatch = list.stream().allMatch(e -> e > 10); //false
boolean noneMatch = list.stream().noneMatch(e -> e > 10); //true
boolean anyMatch = list.stream().anyMatch(e -> e > 4);  //true
 
Integer findFirst = list.stream().findFirst().get(); //1
Integer findAny = list.stream().findAny().get(); //1
 
long count = list.stream().count(); //5
Integer max = list.stream().max(Integer::compareTo).get(); //5
Integer min = list.stream().min(Integer::compareTo).get(); //1

3,2 opération de réduction
        facultative <T> réduire (BinaryOperator < T> accumulateur): La première fois, l'ACC avec le premier argument au premier flux élémentaire, le deuxième paramètre est un second élément d'écoulement élément, une deuxième exécution, le premier paramètre est une fonction du premier résultat de l'exécution, le second paramètre est le troisième élément du courant, et ainsi de suite.
        T réduire (T identité, BinaryOperator < T> accumulateur): Le procédé ci - dessus est le même, mais lorsque la première représentation, le premier paramètre est une fonction d'accumulateur d' identité, et le premier élément du second paramètre est le débit.
        <U> U réduire (identité U , BiFunction <U, super T, U?> Accumulateur, BinaryOperator <U> combinateur): flux série (courant), le procédé avec le second procédé de la même, à savoir, le troisième paramètre combinateur ne fonctionnera pas. En cours d' eau parallèles (parallelStream), on sait que le débit est fourche joindre une pluralité de threads d'exécution, chaque thread de flux d'exécution à ce moment seconde réduire simplement (identité, accumulateur), en tant que troisième paramètre fonction de combineur , chaque fil aspiré résultat d'exécution en tant que nouveau flux, puis utiliser la première méthode de réduire (accumulateur) loi d'écoulement.
 

//经过测试,当元素个数小于24时,并行时线程数等于元素个数,当大于等于24时,并行时线程数为16
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24);
 
Integer v = list.stream().reduce((x1, x2) -> x1 + x2).get(); //相当于把所有数求和
System.out.println(v);   // 300
 
Integer v1 = list.stream().reduce(10, (x1, x2) -> x1 + x2);
System.out.println(v1);  //310
 
Integer v2 = list.stream().reduce(0,
        (x1, x2) -> {
            System.out.println("stream accumulator: x1:" + x1 + "  x2:" + x2);
            return x1 - x2;
        },
        (x1, x2) -> {
            System.out.println("stream combiner: x1:" + x1 + "  x2:" + x2);
            return x1 * x2;
        });
System.out.println(v2); // -300
 
Integer v3 = list.parallelStream().reduce(0,
        (x1, x2) -> {
            System.out.println("parallelStream accumulator: x1:" + x1 + "  x2:" + x2);
            return x1 - x2;
        },
        (x1, x2) -> {
            System.out.println("parallelStream combiner: x1:" + x1 + "  x2:" + x2);
            return x1 * x2;
        });
System.out.println(v3); //197474048

3,3 opération de collecte de
        collecte: la réception d' un exemple Collector, les éléments ont été collectées dans une autre structure de données.
        Collecteur <T, A, R> est une interface avec les 5 méthodes abstraites suivantes:
            Fournisseur du fournisseur <A> (): crée un conteneur de résultat A
            BiConsumer <A, T> ACC avec (): interfaces de consommation, le premier paramètre un récipient a, le second paramètre est l'élément d'écoulement T.
            BinaryOperator <A> combineur (): interface de fonction, le rôle de ce paramètre comme une méthode pour suivre le paramètre combineur (la réduction) ajoutée et les résultats des sous-processus à exécuter en parallèle dans le courant (le récipient d'accumulateur de fonctionnement Une fonction) sont combinés.
            Fonction <A, R> finisseur ( ): interface de fonction, les paramètres sont les suivants : un récipient A, le type de retour est la suivante : Le procédé du résultat final souhaité collecte R.
            Définir <Caractéristiques> Caractéristiques (): renvoie un ensemble de Set immuable pour indiquer les caractéristiques du collecteur. Il y a trois caractéristiques:
                la CONCURRENTES: Indique collecteur de supports concurrency. (Il existe d' autres documents officiels décrivant temporairement pas à explorer, alors ne faites pas trop de traduction)
                Unordered: il indique que les éléments de flux de séquence d'opération de collecte d' origine ne sont pas conservés.
                IDENTITY_FINISH: paramètre représente finisseur identifie simplement peut être ignoré.

3.3.1 bibliothèque d'outils Collector: Collectionneurs

Student s1 = new Student("aa", 10,1);
Student s2 = new Student("bb", 20,2);
Student s3 = new Student("cc", 10,3);
List<Student> list = Arrays.asList(s1, s2, s3);
 
//装成list
List<Integer> ageList = list.stream().map(Student::getAge).collect(Collectors.toList()); // [10, 20, 10]
 
//转成set
Set<Integer> ageSet = list.stream().map(Student::getAge).collect(Collectors.toSet()); // [20, 10]
 
//转成map,注:key不能相同,否则报错
Map<String, Integer> studentMap = list.stream().collect(Collectors.toMap(Student::getName, Student::getAge)); // {cc=10, bb=20, aa=10}
 
//字符串分隔符连接
String joinName = list.stream().map(Student::getName).collect(Collectors.joining(",", "(", ")")); // (aa,bb,cc)
 
//聚合操作
//1.学生总数
Long count = list.stream().collect(Collectors.counting()); // 3
//2.最大年龄 (最小的minBy同理)
Integer maxAge = list.stream().map(Student::getAge).collect(Collectors.maxBy(Integer::compare)).get(); // 20
//3.所有人的年龄
Integer sumAge = list.stream().collect(Collectors.summingInt(Student::getAge)); // 40
//4.平均年龄
Double averageAge = list.stream().collect(Collectors.averagingDouble(Student::getAge)); // 13.333333333333334
// 带上以上所有方法
DoubleSummaryStatistics statistics = list.stream().collect(Collectors.summarizingDouble(Student::getAge));
System.out.println("count:" + statistics.getCount() + ",max:" + statistics.getMax() + ",sum:" + statistics.getSum() + ",average:" + statistics.getAverage());
 
//分组
Map<Integer, List<Student>> ageMap = list.stream().collect(Collectors.groupingBy(Student::getAge));
//多重分组,先根据类型分再根据年龄分
Map<Integer, Map<Integer, List<Student>>> typeAgeMap = list.stream().collect(Collectors.groupingBy(Student::getType, Collectors.groupingBy(Student::getAge)));
 
//分区
//分成两部分,一部分大于10岁,一部分小于等于10岁
Map<Boolean, List<Student>> partMap = list.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 10));
 
//规约
Integer allAge = list.stream().map(Student::getAge).collect(Collectors.reducing(Integer::sum)).get(); //40

3.3.2 Collectors.toList () parse

//toList 源码
public static <T> Collector<T, ?, List<T>> toList() {
    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
            (left, right) -> {
                left.addAll(right);
                return left;
            }, CH_ID);
}
 
//为了更好地理解,我们转化一下源码中的lambda表达式
public <T> Collector<T, ?, List<T>> toList() {
    Supplier<List<T>> supplier = () -> new ArrayList();
    BiConsumer<List<T>, T> accumulator = (list, t) -> list.add(t);
    BinaryOperator<List<T>> combiner = (list1, list2) -> {
        list1.addAll(list2);
        return list1;
    };
    Function<List<T>, List<T>> finisher = (list) -> list;
    Set<Collector.Characteristics> characteristics = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
 
    return new Collector<T, List<T>, List<T>>() {
        @Override
        public Supplier supplier() {
            return supplier;
        }
 
        @Override
        public BiConsumer accumulator() {
            return accumulator;
        }
 
        @Override
        public BinaryOperator combiner() {
            return combiner;
        }
 
        @Override
        public Function finisher() {
            return finisher;
        }
 
        @Override
        public Set<Characteristics> characteristics() {
            return characteristics;
        }
    };
 
}

conclusion

En bref, les caractéristiques flux peut être résumés comme suit:

  • Pas une structure de données
  • Il n'a pas de mémoire interne, il est seulement avec le fonctionnement du pipe-line à partir de la (des structures de données, des réseaux, le fonctionnement du générateur, le canal IO) Source de la récupération de données.
  • Il ne jamais modifier les données sous-jacentes de leur structure de données encapsulées. Par exemple, flux d'opérations de filtrage peut générer un flux filtré ne contient pas de nouveaux éléments, plutôt que de supprimer les éléments de la source.
  • STREAM toutes les opérations doivent être basées sur une expression lambda comme paramètre
  • Il ne supporte pas l'accès indexé
  • Vous pouvez demander le premier élément, mais ne peut pas demander à la deuxième, troisième ou dernier. Toutefois, s'il vous plaît se référer à l'élément suivant.
  • Il est facile de générer un tableau ou liste
  • inertage
  • Beaucoup opération Stream est retard vers l'arrière, jusqu'à ce qu'il a finalement comprendre comment les données beaucoup devront commencer.
  • Toutes les opérations intermédiaires seront toujours inertisées.
  • parallélisme
  • Lorsqu'un flux est parallélisé, il n'y a pas besoin d'écrire du code multithread, toutes ses opérations effectuées automatiquement en parallèle.
  • Il peut être illimité
    • Définir une taille fixe, Stream est pas nécessaire. limite (n) et le fonctionnement sur une telle opération () de court-circuit findFirst peut être fait rapidement et illimité Stream.

 

Article de référence:

Utilisation détaillée du flux Java 8

Java API de flux 8 Commentaires

Java 8 Stream et cartographier le coup d'oeil de différence

Publié 61 articles originaux · louange 9 won · vues 30000 +

Je suppose que tu aimes

Origine blog.csdn.net/qq_33204444/article/details/105029559
conseillé
Classement