Java 8 stream练习

                              Java 8 stream练习

目录

 

构造流的方法

流 ​转化为其他数据结构

流的操作

Map

flatMap

filter

Collectors

Optional

用 Collectors 来进行 reduction 操作

 

统计

小练习

指定字段去重


构造流的方法

// 1. Arrays
String [] strArray = new String[] {"a", "b", "c"};
Stream stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 2. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();

流 ​转化为其他数据结构

// 1. Array
String[] strArray1 = stream.toArray(String[]::new);
// 2. Collection
List<String> list1 = stream.collect(Collectors.toList());
List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
Set set1 = stream.collect(Collectors.toSet());
Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
// 3. String
String str = stream.collect(Collectors.joining()).toString();

流的操作

1) 流的操作类型分为两种:

  • Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
  • Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
  • 还有一种操作被称为 short-circuiting。用以指:
    对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。
    对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。

2) 接下来,当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各类操作了。常见的操作可以归类如下。

  • Intermediate:

    map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

  • Terminal:

forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

  • Short-circuiting:

   anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit

Map


map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());


flatMap

flatMap 把 input Stream 中的层级结构扁平化,就是将最底层元素抽出来放到一起,最终 output 的新 Stream 里面已经没有 List 了,都是直接的数字。

Stream<List<Integer>> inputStream = Stream.of(
 Arrays.asList(1),
 Arrays.asList(2, 3),
 Arrays.asList(4, 5, 6)
 );
Stream<Integer> outputStream = inputStream.
flatMap((childList) -> childList.stream());

filter

filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:
 

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();

Collectors

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
 
System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);

Optional

 在更复杂的 if (xx != null) 的情况中,使用 Optional 代码的可读性更好,而且它提供的是编译时检查,能极大的降低 NPE 这种 Runtime Exception 对程序的影响,或者迫使程序员更早的在编码阶段处理空值问题,而不是留到运行时再发现和调试。

String strA = " abcd ", strB = null;
print(strA);
print("");
print(strB);
getLength(strA);
getLength("");
getLength(strB);
public static void print(String text) {
 // Java 8
 Optional.ofNullable(text).ifPresent(System.out::println);
 // Pre-Java 8
 if (text != null) {
 System.out.println(text);
 }
 }
public static int getLength(String text) {
 // Java 8
return Optional.ofNullable(text).map(String::length).orElse(-1);
 // Pre-Java 8
// return if (text != null) ? text.length() : -1;
 };

用 Collectors 来进行 reduction 操作

java.util.stream.Collectors 类的主要作用就是辅助进行各类有用的 reduction 操作,例如转变输出为 Collection,把 Stream 元素进行归组。

groupingBy/partitioningBy

 按照年龄归组

Map<Integer, List<Person>> personGroups = Stream.generate(new PersonSupplier()). limit(100). collect(Collectors.groupingBy(Person::getAge));
Iterator it = personGroups.entrySet().iterator();
while (it.hasNext()) { 
   Map.Entry<Integer, List<Person>> persons = (Map.Entry) it.next(); 
   System.out.println("Age " + persons.getKey() + " = " + persons.getValue().size());
}

上面的 code,首先生成 100 人的信息,然后按照年龄归组,相同年龄的人放到同一个 list 中,可以看到如下的输出:

Age 0 = 2
Age 1 = 2
Age 5 = 2
Age 8 = 1
Age 9 = 1
Age 11 = 2
……

按照未成年人和成年人归组

Map<Boolean, List<Person>> children = Stream.generate(new PersonSupplier()).
 limit(100).
 collect(Collectors.partitioningBy(p -> p.getAge() < 18));
System.out.println("Children number: " + children.get(true).size());
System.out.println("Adult number: " + children.get(false).size());

输出结果:

Children number: 23 
Adult number: 77

在使用条件“年龄小于 18”进行分组后可以看到,不到 18 岁的未成年人是一组,成年人是另外一组。partitioningBy 其实是一种特殊的 groupingBy,它依照条件测试的是否两种结果来构造返回的数据结构,get(true) 和 get(false) 能即为全部的元素对象。

 

统计

另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
 
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
 
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());
System.out.println("列表个数:" + stats.getCount());


小练习

import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

class Trade {
    private String name;
    private String city;

    public Trade(String name, String city) {
        this.name = name;
        this.city = city;
    }

    @Override
    public String toString() {
        return "Trade{" +
                "name='" + name + '\'' +
                ", city='" + city + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}

class Transaction {
    private Trade trade;
    private int year;
    private int value;

    public Transaction() {

    }

    public Transaction(Trade trade, int year, int value) {
        this.trade = trade;
        this.year = year;
        this.value = value;
    }

    public Trade getTrade() {
        return trade;
    }

    public void setTrade(Trade trade) {
        this.trade = trade;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Transaction{" +
                "trade=" + trade +
                ", year=" + year +
                ", value=" + value +
                '}';
    }
}
public class Demo {
    List<Transaction> transactions = null;

    @Before
    public void before() {
        Trade raoul = new Trade("Raoul", "Cambridge");
        Trade mario = new Trade("Mario", "Milan");
        Trade alan = new Trade("Alan", "Cambridge");
        Trade brian = new Trade("Brian", "Cambridge");
        transactions = Arrays.asList(
                new Transaction(brian, 2011, 300),
                new Transaction(raoul, 2012, 1000),
                new Transaction(raoul, 2011, 400),
                new Transaction(mario, 2012, 710),
                new Transaction(mario, 2012, 700),
                new Transaction(alan, 2012, 950)
        );
    }

    // 找出2011年发生的所有交易,并按交易额排序(从低到高)
    @Test
    public void test1() {
        List<Transaction> res = transactions.stream().
                filter(e -> e.getYear() == 2011).
                sorted((e1,e2) -> Integer.compare(e1.getValue(), e2.getValue())).
                collect(Collectors.toList());
        System.out.println(res);
    }

    // 找出交易员都在哪些不同的城市工作过?
    @Test
    public void test2() {
        List<String> list = transactions.stream().
                map(e -> e.getTrade().getCity()).distinct().
                collect(Collectors.toList());
        System.out.println(list);
    }

    // 查找出所有来自剑桥的交易员,并按姓名排序
    @Test
    public void test3() {
        List<Trade> list = transactions.stream().filter(e -> e.getTrade().getCity().equals("Cambridge")).
                map(e -> e.getTrade()).sorted((e1, e2) -> e1.getName().compareTo(e2.getName())).
                collect(Collectors.toList());
        System.out.println(list);
    }

    // 返回所有交易员的姓名字符串,按字母顺序排序
    @Test
    public void test4() {
        //String result = transactions.stream().map(e -> e.getTrade().getName()).
          //      flatMap(Demo::filterCharacter).
            //    sorted((s1, s2) -> s1.compareToIgnoreCase(s2)).
              //  collect(Collectors.joining());
        //System.out.println(result);

// 流的扁平化
        String result = transactions.stream().map(e -> e.getTrade().getName().split("")).
                flatMap(Arrays::stream). // 将各个生成流扁平化为单个流
                sorted((s1, s2) -> s1.compareToIgnoreCase(s2)).
                collect(Collectors.joining());
        System.out.println(result);
    }

    public static Stream<String> filterCharacter(String str) {
        ArrayList<String> list = new ArrayList<>();
        for (Character c: str.toCharArray()) {
            list.add(c.toString());
        }
        return list.stream();
    }

    // 有没有交易员是在米兰工作的?
    @Test
    public void test5() {
        boolean result = transactions.stream().anyMatch(e -> e.getTrade().getCity().equals("Milan"));
        System.out.println(result);
    }

    // 打印生活在剑桥的交易员的所有交易额
    @Test
    public void test6() {
        Optional<Integer> op = transactions.stream().filter(e -> e.getTrade().getCity().equals("Cambridge")).
                map(Transaction::getValue).
                reduce(Integer::sum);
        System.out.println(op.get());
    }

    // 所有交易中,最高的交易额是多少
    @Test
    public void test7() {
        Optional<Integer> op = transactions.stream().map(Transaction::getValue).
                reduce(Integer::max);
        System.out.println(op.get());
    }

   // 找到交易额最小的交易
   @Test
   public void test8() {
       Optional<Transaction> op = transactions.stream().min(Comparator.comparing(Transaction::getValue));
       System.out.println(op.get());
   }

   // 统计每年的交易额
   @Test
    public void test9() {
       Map<String, Integer> result = transactions.stream().collect(Collectors.toMap(transaction -> String.valueOf(transaction.getYear()), transaction -> transaction.getValue(), (value1, value2) -> value1 + value2));
       System.out.println(result);
   }

}

指定字段去重

class StreamUtil {
    /**
     * 指定字段去重
     * @param keyExtractor
     * @return
     */
    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
}

    @Test
    public  void test10() {
        List<Transaction> list = transactions.stream().filter(StreamUtil.distinctByKey(e -> e.getYear())).collect(Collectors.toList());
        System.out.println(list);
    }

猜你喜欢

转载自blog.csdn.net/xiao__jia__jia/article/details/105472261