java8:流的使用

流的创建和API的基本使用

在java8中提供了一套流式的数据处理,也就是Stream API,这套API的主要作用就是对数据进行处理,流处理相比于迭代处理的好处如下

Stream API 迭代遍历
相当于一套流水线,对数据一次性处理 每次迭代都需要分支进行计算,有时需要多次迭代才能得到最终结果
适应现代多核计算机,在几乎不消耗额外资源的情况下进行多线程遍历 只能单线程遍历,多线程实现起来过于复杂

流的API如下

方法名 功能
distinct() 过滤掉集合中的重复元素
skip(n) 跳过前面N个元素
limit() 获得前面N个元素
filter(T -> boolean) 过滤掉表达式返回false的元素
anyMatch(T -> boolean) 查看集合中是否有符合条件的元素,至少返回一个true
allMatch(T -> boolean) 查看集合中是否均符合条件,所有都需要返回true
noneMatch(T -> boolean) 查看集合中是否均不符合条件,所有都需要返回false
findFirst() 返回第一个元素
findAny() 返回任意一个元素,效率相对上一个高
reduce(T,(T,T) -> T) 将集合所有元素聚合成一个
partitioningBy(T -> boolean) 对集合元素进行分区,也就是一个特殊的分组,只能包含两组
map(T -> R) 将每一个元素T映射成元素R,其中每一个元素都是一条流水线
flatMap(T -> Stream) 每一个元素T映射成元素R,所有元素聚合成一个流
groupingBy(T -> R) 根据对集合元素进行分组

API的使用

public class ExampleOfCaseMain {
    List<Dish> menu;
    List<Transcation> transactions;

    @Before
    public void before() {
        menu = Arrays.asList(
                new Dish("pork", Boolean.FALSE, 800, Dish.Type.MEAT),
                new Dish("beef", Boolean.FALSE, 700, Dish.Type.MEAT),
                new Dish("chicken", Boolean.FALSE, 400, Dish.Type.MEAT),
                new Dish("french fries", Boolean.TRUE, 530, Dish.Type.OTHER),
                new Dish("rice", Boolean.TRUE, 350, Dish.Type.OTHER),
                new Dish("season fruit", Boolean.TRUE, 120, Dish.Type.OTHER),
                new Dish("pizza", Boolean.TRUE, 550, Dish.Type.OTHER),
                new Dish("prawns", Boolean.FALSE, 300, Dish.Type.FISH),
                new Dish("salmon", Boolean.FALSE, 450, Dish.Type.FISH)
        );
    }

     /**
     * 需求:筛选出能量大于300的不重复的元素的第二个和第三个
     * distinct():过滤掉集合中的重复元素
     * skip(n):跳过前面N个元素
     * limit(n):获得前面N个元素
     * filter(T -> boolean):过滤掉表达式返回false的元素
     */
    @Test
    public void test0() {
        List<Dish> collect = menu.stream()
                .filter(d -> d.getCalories() > 300)
                .distinct()
                .skip(1)
                .limit(2)
                .collect(toList());
        System.out.println(collect);
        /**结果:[Dish(name=beef, vegetarian=false, calories=700, type=MEAT), 
        		Dish(name=chicken, vegetarian=false, calories=400, type=MEAT)]
        */
    }

    /**
     * 匹配:
     * anyMatch(T -> boolean):查看集合中是否有符合条件的元素,至少返回一个true
     * allMatch(T -> boolean):查看集合中是否均符合条件,所有都需要返回true
     * noneMatch(T -> boolean):查看集合中是否均不符合条件,所有都需要返回false
     * 查找:
     * findFirst():返回第一个元素
     * findAny():返回任意一个元素,效率相对上一个高
     * reduce(T,(T,T) -> T):将集合所有元素聚合成一个
     * partitioningBy(T -> boolean):对集合元素进行分区,也就是一个特殊的分组,只能包含两组
     */
    @Test
    public void test1(){
        //有没有叫pork的
        System.out.println(menu.stream().anyMatch(d -> "pork".equals(d.getName())));
        //是不是都叫pork
        System.out.println(menu.stream().allMatch(d -> "pork".equals(d.getName())));
        //是不是没有pork
        System.out.println(menu.stream().noneMatch(d -> "pork".equals(d.getName())));
        //查找第一个dish
        System.out.println(menu.stream().findAny());
        System.out.println(menu.stream().findFirst());
        //将所有dish的名字进行拼接
        System.out.println(menu.stream().map(Dish::getName).reduce((a,b)->a+b));
        /**
         * 结果如下
		 * true
		 * false
		 * false
		 * Optional[Dish(name=pork, vegetarian=false, calories=800, type=MEAT)]
		 * Optional[Dish(name=pork, vegetarian=false, calories=800, type=MEAT)]
		 * Optional[porkbeefchickenfrench friesriceseason fruitpizzaprawnssalmon]
		 */
    }

    /**
     * map(T -> R):将每一个元素T映射成元素R,其中每一个元素都是一条流水线
     * flatMap(T -> Stream):将每一个元素T映射成元素R,所有元素聚合成一个流
     * groupingBy(T -> R):根据对集合元素进行分组
     */
    @Test
    public void test2() {
        Map<Integer, Long> collect = menu.stream()
                .map(Dish::getName)
                //将每个名字根据长度进行分组,并统计每个组中元素的个数
                .collect(groupingBy(a -> a.length(), counting()));
        System.out.println(collect);
        //进行一个复杂复杂分组,没有实际意义
        Map<Boolean, Map<String, Map<Dish.Type, List<Dish>>>> collect1 = menu.stream()
                .collect(
                		//根据是否为素食分组
                        groupingBy(Dish::isVegetarian,
                        		//根据名称分组
                                groupingBy(Dish::getName,
                                		//根据类型分组
                                        groupingBy(Dish::getType))));
        System.out.println(collect1);
	/**
     * 结果如下
     {4=3, 5=1, 6=2, 7=1, 12=2}
     {
         false = {
             chicken = {
                MEAT = [Dish(name = chicken, vegetarian = false, calories = 400, type = MEAT)]
             },
             salmon = {
                FISH = [Dish(name = salmon, vegetarian = false, calories = 450, type = FISH)]
             },
             beef = {
                MEAT = [Dish(name = beef, vegetarian = false, calories = 700, type = MEAT)]
             },
             pork = {
                MEAT = [Dish(name = pork, vegetarian = false, calories = 800, type = MEAT)]
             },
             prawns = {
                FISH = [Dish(name = prawns, vegetarian = false, calories = 300, type = FISH)]
             }
         },
         true = {
             season fruit = {
                OTHER = [Dish(name = season fruit, vegetarian = true, calories = 120, type = OTHER)]
             },
             pizza = {
                OTHER = [Dish(name = pizza, vegetarian = true, calories = 550, type = OTHER)]
             },
             rice = {
                OTHER = [Dish(name = rice, vegetarian = true, calories = 350, type = OTHER)]
             },
             french fries = {
                OTHER = [Dish(name = french fries, vegetarian = true, calories = 530, type = OTHER)]
             }
         }
     }
     */
    }

实际需求中的应用

public class ExampleOfCaseMain {
    List<Transcation> transactions;

    @Before
    public void before() {
        //交易员
        Trader raoul = new Trader("Raoul", "Cambridge");
        Trader mario = new Trader("Mario", "Milan");
        Trader alan = new Trader("Alan", "Cambridge");
        Trader brian = new Trader("Brian", "Cambridge");

        //交易记录
        transactions = Arrays.asList(
                new Transcation(brian, 2011, 300),
                new Transcation(raoul, 2012, 1000),
                new Transcation(raoul, 2011, 400),
                new Transcation(mario, 2012, 710),
                new Transcation(mario, 2012, 700),
                new Transcation(alan, 2012, 950)
        );
    }
    /**
     * 需求:
     * 1.找出2011年发生的所有交易,并按交易额排序(从低到高)
     * 2.交易员都在哪些不同的城市工作过?
     * 3.查找所有来自剑桥的交易员,并按姓名排序。
     * 4.返回所有交易员的姓名字符串,按字母顺序排序。
     * 5.有没有交易员是在米兰工作的?
     * 6.打印生活在剑桥的交易员的所有交易额。
     * 7.所有交易中,最高的交易额是多少?
     * 8.找到交易额最小的交易。
     */
    @Test
    public void test1() {
        List<Transcation> collect = transactions.stream()
                .filter(t -> 2011 == t.getYear())
                .sorted(comparing(a -> a.getValue()))//默认由低到高排序,如果想由高到低排序加一个"-"号
                .collect(toList());
        System.out.println(collect);
    }

    @Test
    public void test2() {
        List<String> collect = transactions.stream()
                .map(t -> t.getTrader().getCity())
                .distinct()
                .collect(toList());
        System.out.println(collect);
    }

    @Test
    public void test3() {
        List<Trader> collect = transactions.stream()
                .map(Transcation::getTrader)
                .distinct()
                .filter(trader -> "Cambridge".equals(trader.getCity()))
                .sorted(comparing(Trader::getName))
                .collect(toList());
        System.out.println(collect);
    }

    @Test
    public void test4() {
        List<String> collect = transactions.stream()
                .map(t -> t.getTrader().getName())
                .distinct()
                .sorted()//可以使用reverseOrder()对字符串集合进行倒序输出
                .collect(toList());
        System.out.println(collect);
    }

    @Test
    public void test5() {
        boolean milan = transactions.stream()
                .map(t -> t.getTrader().getCity())
                .anyMatch(c -> "Milan".equals(c));
        System.out.println(milan);
    }

    @Test
    public void test6() {
        Optional<Integer> cambridge = transactions.stream()
                .filter(t -> "Cambridge".equals(t.getTrader().getCity()))
                .map(t -> t.getValue())
                .reduce(Integer::sum);
        System.out.println(cambridge.get());
        //优化,使用数值流,节约了拆箱装箱的成本
        double sum = transactions.stream()
                .filter(t -> "Cambridge".equals(t.getTrader().getCity()))
                .mapToDouble(t -> t.getValue())
                .sum();
        System.out.println(sum);
    }

    @Test
    public void test7() {
        Optional<Integer> cambridge = transactions.stream()
                .filter(t -> "Cambridge".equals(t.getTrader().getCity()))
                .map(t -> t.getValue())
                .reduce(Integer::max);
        System.out.println(cambridge.get());
    }

    @Test
    public void test8() {
        Optional<Transcation> reduce = transactions.stream()
                .filter(t -> "Cambridge".equals(t.getTrader().getCity()))
                .reduce((a, b) -> a.getValue() < b.getValue() ? a : b);
        System.out.println(reduce.get());
    }

}

你可能感兴趣的:(java8)