Java Stream流

Java Stream流

认识Stream流

  • 是Jdk8开始新增的一套API(java.util.stream.*),可以用于操作集合或者数组的数据
  • 优势:Stream流大量的结合了Lambda的语法风格来编程,功能强大、性能高效、代码简洁、可读性好

代码体验

package com.itheima.stream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class StreamDemo1 {
    public static void main(String[] args) {
        // 认识Stream流
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张三");
        list.add("张翠兰");

        System.out.println(list);

        List<String> newList = new ArrayList<>();
        for (String name : list) {
            if (name.startsWith("张") && name.length() == 2) {
                newList.add(name);
            }
        }
        System.out.println(newList);

        // 使用Stream流解决
        List<String> newList1 = list.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3).collect(Collectors.toList()); // filter 过滤
        System.out.println(newList1);
    }
}

Stream流的使用步骤

准备数据源(集合、数组、…)→ 过滤 → 排序 → 去重→ … →获取结果

  • 1.获取Stream流,Stream流代表着一条流水线,并能与数据源建立连接;
  • 2.调用流水线各种方法,对数据进行处理;
  • 3.获取处理的数据,遍历、统计、收集到一个新的集合中返回结果。

获取Stream流

  • 获取 **集合 ** 的Stream流
Collection 提供的如下方法 说明
default Stream stream() 获取当前集合对象的 Stream 流
  • 获取 **数组 ** 的Stream流
Arrays 类提供的如下方法 说明
public static Stream stream(T[] array) 获取当前数组的 Stream 流
Stream 类提供的如下方法 说明
public static Stream of(T… values) 获取当前接收数据的 Stream 流

代码实例

package com.itheima.stream;

import java.util.*;
import java.util.stream.Stream;

public class StreamDemo2 {
    public static void main(String[] args) {
        // 1.获取集合的Stream流
        Collection<String> list = new ArrayList<>();
        Stream<String> s = list.stream();

        // 2.获取Map集合的Stream流
        Map<String, Integer> map = new HashMap<>();
        // map.stream(); // 不能直接调用stream
        // 获取键流
        Stream<String> keyStream = map.keySet().stream();
        // 获取值流
        Stream<Integer> valueStream = map.values().stream();
        // 获取键值对流
        Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();

        // 获取数组的Stream流
        String[] name = {"张无忌", "赵敏", "张强", "张三丰", "张翠山", "张小强"};
        Stream<String> stream = Arrays.stream(name); // 方式1
        Stream<String> stream1 = Stream.of("张无忌", "赵敏"); // 方式2       
    }
}

Stream流提供的常用方法

  • 中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。
Stream 提供的常用中间方法 说明
Stream filter(Predicate predicate) 用于对流中的数据进行过滤
Stream sorted() 对元素进行升序排序
Stream sorted(Comparator comparator) 按照指定规则排序
Stream limit(long maxSize) 获取前几个元素
Stream skip(long n) 跳过前几个元素
Stream distinct() 去除流中重复的元素
Stream map(Function mapper) 对元素进行加工,并返回对应的新流
static Stream concat(Stream a, Stream b) 合并 a 和 b 两个流为一个流

代码实例

package com.itheima.stream;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class StreamDemo3 {
    public static void main(String[] args) {
        // 掌握Stream流常用的中间方法
        // 1.对流中的数据进行过滤
        List<String> list = new ArrayList<>();
        list.add("张三丰");
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三");
        list.add("张翠兰");
        list.add("张晓强");
        System.out.println(list);
        System.out.println("--------------------------对流中的数据进行过滤--------------------------");
        list.stream().filter(name -> name.startsWith("张") && name.length() == 3).forEach(System.out::println);
        // 2.对元素进行升序排序
        System.out.println("--------------------------对元素进行升序排序--------------------------");
        List<Double> list1 = new ArrayList<>();
        // 无规律添加成绩,有小数点
        list1.add(99.5);
        list1.add(88.9);
        list1.add(88.9);
        list1.add(76.9);
        list1.add(98.7);
        list1.add(65.4);
        list1.add(87.2);

        list1.stream().sorted((o1, o2) -> Double.compare(o1, o2)).forEach(System.out::println); // 升序排序
        // 3.对元素进行降序排序
        System.out.println("--------------------------对元素进行降序排序--------------------------");
        list1.stream().sorted((o1, o2) -> Double.compare(o2, o1)).forEach(System.out::println); // 降序排序
        // 4.获取前几个元素
        System.out.println("--------------------------获取前几个元素--------------------------");
        list.stream().limit(3).forEach(System.out::println);
        // 5.跳过前几个元素
        System.out.println("--------------------------跳过前几个元素--------------------------");
        list1.stream().skip(2).forEach(s -> System.out.println(s));
        // 6.去重
        System.out.println("--------------------------去重--------------------------");
        list1.stream().distinct().forEach(System.out::println);
        // 7.映射/加工方法,返回对应的新Stream流
        System.out.println("--------------------------映射/加工方法,返回对应的新Stream流--------------------------");
        // 每个学生加5分,加分超过100分的,则变为100分
        list1.stream().map(s -> (s + 5) > 100 ? 100 : s + 5).forEach(System.out::println);

        // 8.合并流
        System.out.println("--------------------------合并流--------------------------");
        Stream<Object> concat = Stream.concat(list.stream(), list1.stream());
        concat.forEach(System.out::println);
    }
}

终结方法、收集Stream流

Stream流的终结方法

  • 终结方法指的是调用完成后,不会返回新Stream了,没法继续使用流了。
Stream 提供的常用终结方法 说明
void forEach(Consumer action) 对此流运算后的元素执行遍历
long count() 统计此流运算后的元素个数
Optional max(Comparator comparator) 获取此流运算后的最大值元素
Optional min(Comparator comparator) 获取此流运算后的最小值元素

收集Stream流

  • 收集Stream流:就是把Stream流操作后的结果转回到集合或者数组中去返回
    • 集合/数组:才是开发中的目的
    • Stream流:方便操作集合/数组的手段
Stream 提供的常用终结方法 说明
R collect(Collector collector) 把流处理后的结果收集到一个指定的集合中去
Object[] toArray() 把流处理后的结果收集到一个数组中去
Collectors 工具类提供的具体收集方式 说明
public static Collector toList() 把元素收集到 List 集合中
public static Collector toSet() 把元素收集到 Set 集合中
public static Collector toMap(Function keyMapper , Function valueMapper) 把元素收集到 Map 集合中

代码实例

package com.itheima.stream;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Comparator.comparingDouble;

public class StreamDemo4 {
    public static void main(String[] args) {
        // Stream流的终结方法
        List<Teacher> teacher = new ArrayList<>();
        teacher.add(new Teacher("张三丰", 50, 51000));
        teacher.add(new Teacher("张无忌", 20, 20000));
        teacher.add(new Teacher("周芷若", 18, 18000));
        teacher.add(new Teacher("赵敏", 16, 16000));
        teacher.add(new Teacher("金毛狮王", 60, 33000));

        System.out.println(teacher);
        // Stream的终结方法
        // 1.forEach
        System.out.println("------------------------------forEach终结方法------------------------------");
        teacher.stream().filter(t -> t.getAge() > 30 && t.getSalary() > 30000).forEach(System.out::println);

        // 2.count
        System.out.println("------------------------------count终结方法------------------------------");
        System.out.println(teacher.stream().filter(t -> t.getAge() > 30 && t.getSalary() > 30000).count());

        // 3.max
        System.out.println("------------------------------max终结方法------------------------------");
        Optional<Teacher> max = teacher.stream().max((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));
        // 简化代码
        Optional<Teacher> max1 = teacher.stream().max(comparingDouble(Teacher::getSalary));
        Teacher maxTeacher = max.get();
        System.out.println(maxTeacher);

        // 4.min
        System.out.println("------------------------------min终结方法------------------------------");
        Optional<Teacher> min = teacher.stream().min((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));
        Teacher minTeacher = min.get();
        System.out.println(minTeacher);


        // Stream的收集方法,Collectors 工具类提供的具体收集方式
        System.out.println("------------------------------collectors收集方法------------------------------");
        List<String> name = new ArrayList<>();
        name.add("张三丰");
        name.add("张无忌");
        name.add("张无忌");
        name.add("周芷若");
        name.add("赵敏");
        name.add("张强");
        name.add("张三");
        name.add("张翠兰");
        name.add("张晓强");

        // 收集到List集合
        System.out.println("--------------------------收集到List集合--------------------------");
        Stream<String> s1 = name.stream().filter(n -> n.startsWith("张") && n.length() == 3);
        List<String> s1List = s1.collect(Collectors.toList());
        System.out.println(s1List);

        // 收集到Set集合
        System.out.println("--------------------------收集到Set集合--------------------------");
        HashSet<Object> s1Set = new HashSet<>();
        s1Set.addAll(s1List);
        System.out.println(s1Set);

        // 收集到Map集合
        System.out.println("--------------------------收集到Map集合--------------------------");
        Stream<Teacher> s2 = teacher.stream().filter(t -> t.getAge() > 15);
        Map<String, Double> map = s2.collect(Collectors.toMap(Teacher::getName, Teacher::getSalary));
        System.out.println(map);

        // 收集到数组
        System.out.println("--------------------------收集到数组--------------------------");
        Stream<String> s3 = name.stream().filter(n -> n.startsWith("张") && n.length() == 3);
        Object[] array = s3.toArray();
        System.out.println(Arrays.toString(array));
    }
}

方法中的可变参数(拓展)

  • 就是一种特殊形参,定义在方法、构造器的形参列表里,格式是:数据类型…参数名称;
  • 可变参数的特点和好处
    • 特点:可以不传数据给它;可以传一个或者同时传多个数据给它;也可以传一个数组给它。
    • 好处:常常用来灵活的接收数据。
  • 可变参数的注意事项:
    • 可变参数在方法内部就是一个数组
    • 一个形参列表中可变参数只能有一个
    • 可变参数必须放在形参列表的最后面

Collections工具类

  • Collections ——一个用来操作集合的工具类
  • Collections提供的常用静态方法
方法名称 说明
public static boolean addAll(Collection c, T… elements) 给集合批量添加元素
public static void shuffle(List list) 打乱 List 集合中的元素顺序
public static void sort(List list) 对 List 集合中的元素进行升序排序
public static void sort(List list, Comparator c) 对 List 集合中元素,按照比较器对象指定的规则进行排序

案例——斗地主游戏设计

  • 业务需求:
    • 总共有54张牌
    • 点数:“3” “4” “5” “6” “7” “8” “9” “10” “J” “Q” “K” “A” “2”
    • 花色:4种花色
    • 大小王
    • 斗地主:发出51张牌,剩下3张做为底牌
  • 分析实现
  • 在启动游戏房间的时候,应该提前准备好54张牌接着,需要完成洗牌、发牌、对牌排序、看牌

代码实例

启动游戏

package com.itheima.stream;

public class Game {
    public static void main(String[] args) {
        // 开发斗地主游戏
        // 每张牌都以一个对象,定义Card类
        // 每个游戏房间都是一个对象,定义一个GameRoom类
        new GameRoom().start();

    }
}

创建一个Card类,用于封装Card对象的特征

package com.itheima.stream;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor

public class Card {
    // 定义牌的号码size和牌的花色
    private String size;
    private String color;
    private int num;

    @Override
    public String toString() {
        return size + color;
    }
}

创建一个游戏Room

  • 完成牌的初始化,洗牌,发牌,留出底牌,看牌,给任意玩家底牌,给牌排序等功能
package com.itheima.stream;

import java.util.*;

public class GameRoom {
    // 1.准备牌,定义一个集合,存储54张牌
    private List<Card> allCards = new ArrayList<>();

    //2.初始化54张牌,用实例代码块(示例代码块和对象一起初始化)
    {
        String[] sizes = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
        String[] colors = {"♥", "♦", "♣", "♠"};
        // 两个循环进行牌的匹配
        int num = 0;
        for (String size : sizes) {
            num++;
            for (String color : colors) {
                // 创建牌对象,并添加到集合中
                Card card = new Card(size, color, num);
                // 添加到allCards集合中
                allCards.add(card);
            }
        }
        // 创建大小王并添加到集合中去
        Collections.addAll(allCards, new Card("", "", ++num), new Card("", "", ++num));
        // 查看新牌
        System.out.println("原始牌:" + allCards);
    }

    public void start() {
        // 3.洗牌,洗牌就是打乱集合中的顺序
        Collections.shuffle(allCards);
        System.out.println("洗牌后:" + allCards);

        // 4.发牌,定义三个玩家player:老王、老李、老朱,三个玩家对应着三个集合,因此使用Map集合,玩家是键,牌的集合是值
        Map<String, List<Card>> players = new HashMap<>();
        List<Card> lw = new ArrayList<>();
        players.put("老王", lw);
        List<Card> ll = new ArrayList<>();
        players.put("老李", ll);
        List<Card> lz = new ArrayList<>();
        players.put("老朱", lz);

        for (int i = 0; i < allCards.size() - 3; i++) {
            if (i % 3 == 0) {
                lw.add(allCards.get(i));
            }else if(i % 3 == 1) {
                ll.add(allCards.get(i));
            }else {
                lz.add(allCards.get(i));
            }
        }

        // 5.看牌,遍历Map集合
        for (Map.Entry<String, List<Card>> entry : players.entrySet()){
            // 获取玩家姓名
            String key = entry.getKey();
            // 获取牌的集合
            List<Card> value = entry.getValue();
            System.out.println(key + "的牌为:" + value);
        }
        // 底牌
        // subList(int fromIndex, int toIndex) 是 List 接口提供的一个方法,用于截取列表中的一部分元素,返回一个新的子列表
        List<Card> lastCard = allCards.subList(allCards.size() - 3, allCards.size());
        System.out.println("底牌:" + lastCard);

        // 6.随机选一个玩家将底牌交给玩家
        String key = players.keySet().toArray()[new Random().nextInt(players.size())].toString();
        players.get(key).addAll(lastCard);

        // 7.给牌排序(增加一个排序属性)
        sortCard(lw);
        System.out.println("老王的牌:" + lw);
        sortCard(ll);
        System.out.println("老李的牌:" + ll);
        sortCard(lz);
        System.out.println("老朱的牌:" + lz);

    }

    private void sortCard(List<Card> cards) {
        // 牌排序
        Collections.sort(cards, new Comparator<Card>() {
            @Override
            public int compare(Card o1, Card o2) {
                // 牌大小排序
                return o2.getNum() - o1.getNum();
            }
        });
    }

}

你可能感兴趣的:(java,windows,开发语言)