筛选(fillter)和切片、map

 

学习笔记,源代码在GitHub上:https://github.com/chenquan1992/java_8_in_action.git

这都是java 8 in action书上的源代码

public static List<Integer> getLowCaloricDishesNamesInJava8(List<Dish> dishes){
    return dishes.stream()
            .filter(d -> d.getCalories() > 400)
            .limit(3) // debug的时候看集合顺序,取的前三条
            .skip(2)  //  debug的时候看集合顺序,跳过了前两条不取,取剩下的
            .distinct()  //只保留不同元素的,根据流所生成元素的 hashCode 和 equals 方法实现(去重复,使唯一,值一样,内存地址不同,也能去重复)这个也有顺序位置的关系,最好放在map之后
            .sorted(comparing(Dish::getCalories))//Dish::getCalories 方法应用,看做是调用Dish中的getCalories方法这样去理解
            .map(Dish::getCalories) // map 这个方法相当于 调用了 getCalories 的方法,将他返回的值存在map中,然后
            .collect(toList());// 在这里操作成一个集合可以返回
}
// map
List<Integer> dishNames = menu.stream()
                             .map(Dish::getName)  //调用Dish中的getName方法,获取到所有名字的流
                             .map(String::length) //使用上面的流继续操作,调用String的length的方法获取到长度的流,
                             .collect(toList()); //将这些流变成一个集合返回
System.out.println(dishNames);
    // flatMap
        System.out.println("=========================================================================================");
        List<Integer> numbers1 = Arrays.asList(1,2,3,4,5);
        List<Integer> numbers2 = Arrays.asList(6,7,8);
        List<int[]> pairs =
                        numbers1.stream()
                                .flatMap((Integer i) -> { // 有流返回到这里    二
                                    System.out.println("i = "+i);
                                    return numbers2.stream()
                                                       .map((Integer j) ->{
                                                             System.out.println("j = "+j);
                                                             return new int[]{i, j}; //当这里有返回的时候,自然的就会运行下面的fillter  一
                                                       });
//                                                        .filter(pair -> {  //注销的这段与下面的效果相同
//                                                            System.out.println("pair 1 = (" + pair[0]+ ","+pair[1]+")");
//                                                            return (pair[0] + pair[1]) % 3 == 0;
//                                                        });
                                })
                                .filter(pair -> { //自然就会运行这里    三
                                    System.out.println("pair 2 = (" + pair[0]+ ","+pair[1]+")");
                                    return (pair[0] + pair[1]) % 3 == 0;
                                })
                                .collect(toList());
List<Long> collect = products.stream()
        .filter(p -> {
            System.out.println("测试打印次数:过滤");
            return p.getPrice() > 700 && p.getPrice() < 7000;
        })
        .map((Product p )-> {
            System.out.println("测试打印次数:map");
            return p.getPrice();
        })
        .collect(toList());
private static boolean isVegetarianFriendlyMenu(){
    return menu.stream().anyMatch(Dish::isVegetarian);//任何匹配:只要条件有一个返回true,就是true
}

private static boolean isHealthyMenu(){//全部匹配:只有条件全部是true,才能是true
    return menu.stream().allMatch(d -> d.getCalories() < 1000);
}

private static boolean isHealthyMenu2(){//没有匹配:只要条件全都是false,才是true
    return menu.stream().noneMatch(d -> d.getCalories() >= 1000);
}
 

sorted的用法

// Query 1: Find all transactions from year 2011 and sort them by value (small to high).
      List<Transaction> tr2011 = transactions.stream()
              .filter(transaction -> transaction.getYear() == 2011)
              .sorted(comparing(Transaction::getValue).reversed()) //comparing(Transaction::getValue) 正序排序,   .reversed()反转顺序,还可以直接 .sorted()只要list可以直接排序
              .collect(toList());
      System.out.println(tr2011);

      List<Transaction> cambridge111 = transactions.stream()
              .filter(t -> t.getTrader().getCity().equals("Cambridge"))
              .sorted(comparing(p -> p.getTrader().getName())) //这里,能不能倒序啊?
              .collect(toList());
int calories = menu.stream()
                   .mapToInt(Dish::getCalories)
                   .sum();
System.out.println("Number of calories:" + calories);

Map分组

public static List<Transaction> transactions = Arrays.asList( new Transaction(Currency.EUR, 1500.0),
                                                              new Transaction(Currency.USD, 2300.0),
                                                              new Transaction(Currency.GBP, 9900.0),
                                                              new Transaction(Currency.EUR, 1100.0),
                                                              new Transaction(Currency.JPY, 7800.0),
                                                              new Transaction(Currency.CHF, 6700.0),
                                                              new Transaction(Currency.EUR, 5600.0),
                                                              new Transaction(Currency.USD, 4500.0),
                                                              new Transaction(Currency.CHF, 3400.0),
                                                              new Transaction(Currency.GBP, 3200.0),
                                                              new Transaction(Currency.USD, 4600.0),
                                                              new Transaction(Currency.JPY, 5700.0),
                                                              new Transaction(Currency.EUR, 6800.0) );

java 7写法

private static void groupImperatively() {
    Map<Currency, List<Transaction>> transactionsByCurrencies = new HashMap<>();//建立累积交易分组的 Map,分组使用Map最好
    for (Transaction transaction : transactions) {
        Currency currency = transaction.getCurrency();//提取Transaction 的货币
        List<Transaction> transactionsForCurrency = transactionsByCurrencies.get(currency);//根据货币获取分组条目,根据类别获取Map
        if (transactionsForCurrency == null) {//如果分组Map中没有这种货币的条目,就创建一个,没有就新增分组,还要给list空间
                transactionsForCurrency = new ArrayList<>();
            transactionsByCurrencies.put(currency, transactionsForCurrency);
        }
        transactionsForCurrency.add(transaction);//将当前遍历的Transaction 加入同一货币的Transaction 的List,然后就把分组内存存进去
    }

    System.out.println(transactionsByCurrencies);
}

java 8写法

private static void groupFunctionally() {
    Map<Currency, List<Transaction>> transactionsByCurrencies = transactions.stream().collect(groupingBy(Transaction::getCurrency));
    System.out.println(transactionsByCurrencies);
}

汇总

private static IntSummaryStatistics calculateMenuStatistics() {
    return menu.stream().collect(summarizingInt(Dish::getCalories));

}

打印calculateMenuStatistics()会得到以下输出:IntSummaryStatistics{count=9, sum=4300, min=120,average=477.777778, max=800}

同样,相应的summarizingLong和summarizingDouble工厂方法

连接字符串

String shortMenu = menu.stream().map(Dish::getName).collect(joining(", "));

它会生成:pork, beef, chicken, french fries, rice, season fruit, pizza, prawns, salmon

相同的结果

int totalCalories = menu.stream().map(Dish::getCalories).reduce(Integer::sum).get();

int totalCalories = menu.stream().mapToInt(Dish::getCalories).sum();

自定义分组

public enum CaloricLevel { DIET, NORMAL, FAT }
private static Map<CaloricLevel, List<Dish>> groupDishesByCaloricLevel() {
    return menu.stream().collect(
            groupingBy(dish -> {
                if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                else return CaloricLevel.FAT;
            } ));
}

多级分组

private static Map<Dish.Type, Map<CaloricLevel, List<Dish>>> groupDishedByTypeAndCaloricLevel() {
    return menu.stream().collect(
            groupingBy(Dish::getType,//一级分类
                    groupingBy((Dish dish) -> {//二级分类
                        if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                        else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                        else return CaloricLevel.FAT;
                    } )
            )
    );
}

分组计算数值

private static Map<Dish.Type, Long> countDishesInGroups() {
    return menu.stream().collect(groupingBy(Dish::getType, counting()));
}

结果:{MEAT=3, FISH=2, OTHER=4}

分组:以热量最大的最为组员

Map<Dish.Type, Optional<Dish>> mostCaloricByType =

        menu.stream()

                 .collect(groupingBy(Dish::getType,maxBy(comparingInt(Dish::getCalories))));//找出热量最大的

这个分组的结果显然是一个map,以Dish的类型作为键,以包装了该类型中热量最高的Dish的Optional<Dish>作为值:

{FISH=Optional[salmon], OTHER=Optional[pizza], MEAT=Optional[pork]}

查找每个子组中热量最高的Dish

Map<Dish.Type, Dish> mostCaloricByType =
    menu.stream()
        .collect(groupingBy(Dish::getType,
            collectingAndThen(
                maxBy(comparingInt(Dish::getCalories)),
                    Optional::get)));

其结果是下面的Map:{FISH=salmon, OTHER=pizza, MEAT=pork}

private static Map<Dish.Type, Integer> sumCaloriesByType() {
    return menu.stream().collect(groupingBy(Dish::getType,
            summingInt(Dish::getCalories)));
}
private static Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType() {
    return menu.stream().collect(
            groupingBy(Dish::getType, mapping(
                    dish -> { if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                    else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                    else return CaloricLevel.FAT; },
                    toSet() )));
}

这里,就像我们前面见到过的,传递给映射方法的转换函数将Dish映射成了它的
CaloricLevel:生成的CaloricLevel流传递给一个toSet收集器,它和toList类似,不过是
把流中的元素累积到一个Set而不是List中,以便仅保留各不相同的值。如先前的示例所示,这
个映射收集器将会收集分组函数生成的各个子流中的元素,让你得到这样的Map结果:

{OTHER=[DIET, NORMAL], MEAT=[DIET, NORMAL, FAT], FISH=[DIET, NORMAL]}

Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType =
menu.stream().collect(
groupingBy(Dish::getType, mapping(
dish -> { if (dish.getCalories() <= 400) return CaloricLevel.DIET;
else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
else return CaloricLevel.FAT; },

toCollection(HashSet::new) )));

分区

private static Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType() {
    return menu.stream().collect(partitioningBy(Dish::isVegetarian,//分区函数
                                                groupingBy(Dish::getType)));//第二个收集器
}

这将产生一个二级 Map :

{false={FISH=[prawns, salmon], MEAT=[pork, beef, chicken]},

true={OTHER=[french fries, rice, season fruit, pizza]}}

private static Object mostCaloricPartitionedByVegetarian() {
    return menu.stream().collect(
            partitioningBy(Dish::isVegetarian,
                    collectingAndThen(
                            maxBy(comparingInt(Dish::getCalories)),
                            Optional::get)));
}

{false=pork, true=pizza}

public boolean isPrime(int candidate) {
    return IntStream.range(2, candidate)//产生一个自然数范围,从2开始,直至但不包括待测数
                                .noneMatch(i -> candidate % i == 0);//如果待测数字不能被流中任何数字整除则返回 true
}

在需要将数值范围装箱成为一个一般流时, boxed 尤其有用

IntStream intStream = IntStream.rangeClosed(2, n);
Stream<Integer> boxed = IntStream.rangeClosed(2, n).boxed();
Map<Boolean, List<Integer>> collect = IntStream.rangeClosed(2, n).boxed()
                        .collect(partitioningBy(candidate -> isPrime(candidate)));

猜你喜欢

转载自blog.csdn.net/otiankuaile/article/details/80534737