Java Stream API

   

   

        jdk1.8中新特性java Stream Api的呈现是java函数式编程引入之后的魔法糖之一。Stram API主要对流进行函数操作,使你的代码更简洁易读,更灵活,性能更好。我们通过以下几方面介绍Stream Api如何让我们的代码更加丝滑。

1.创建流

       流的创建直接使用Stream类的方法进行创建。

 1.1.创建空流

Stream<Integer> emptyStream = Stream.empty();

1.2.根据数组和集合创建流

//根据数组创建流
        int[] intArray = new int[]{1,3,4,5,7};
        IntStream intStream = Arrays.stream(intArray);

        Stream<Integer> integerStream = Stream.of(1,2,34,5,6);

        //通过集合创建数组
        List<String> strList = Arrays.asList("a","b","c");
        Stream<String> stringStream = strList.stream();

        Set<String> strSet = new HashSet<>(strList);
        Stream<String> stringStream1 = strSet.stream();

1.3.创建无限流

Stream<Integer> generateStream = Stream.generate(()->new Random().nextInt());
        Stream<Integer> iterateStream=Stream.iterate(1,x->x+1);

 

 

2.流的操作

        关于流的操作主要有map,sorted,filter,collect等方法具体的使用细节,以下通过一个实例来讲解一下。

Trader.java

public class Trader {
    private final String name;

    private final String city;

    public Trader(String n,String c){
        this.name=n;
        this.city=c;
    }

    public String getName() {
        return name;
    }

    public String getCity() {
        return city;
    }

    public String toString(){
        return "Trader:"+this.name+" in "+this.city;
    }
}

Transaction.java

public class Transaction {

    private final Trader trader;
    private final int year;

    private final int value;

    public Transaction(Trader trader,int year,int value){
        this.trader = trader;
        this.year = year;
        this.value = value;
    }

    public Trader getTrader() {
        return trader;
    }

    public int getYear() {
        return year;
    }

    public int getValue() {
        return value;
    }

    public String toString(){
        return "{"+this.trader+", "+"year: "+this.year+", "+"value:"+this.value+"}";
    }
}

 TransactionUtil.java

public class TransactionUtil {


    private static List<Transaction> init(){
        Trader raoul=new Trader("Raoul", "Cambridge");
        Trader mario=new Trader("Mario", "Milan");
        Trader alan=new Trader("Alan", "Cambridge");
        Trader brian=new Trader("Brian", "Cambridge");


        List<Transaction> 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),
                new Transaction(mario, 2013, 710),
                new Transaction(mario, 2013, 700),
                new Transaction(raoul, 2013, 950)
        );
        return transactions;
    }

    public static void main(String[] args){
        List<Transaction> transactionList = init();
        List<Integer> yearList = new ArrayList<>();
        //获取所有交易对应的年份
        yearList = transactionList.stream()
                                  .map(Transaction::getYear)
                                  .collect(toList());

        //排序
        List<Transaction> sortedTransactionList = new ArrayList<>();
        sortedTransactionList = transactionList.stream()
                                               .sorted(comparing(Transaction::getValue))
                                               .collect(toList());//comparing作为比较函数
        System.out.println("sortedTransactionList:"+sortedTransactionList);

        //分块
        Map<Boolean,List<Transaction>> partitionMap = transactionList.stream()
                .collect(partitioningBy(transaction -> transaction.getValue()>600));
        System.out.println("partitionMap:"+partitionMap);
        //分组
        Map<Integer,List<Transaction>> map = new HashMap<>();
        map = transactionList.stream()
                             .collect(groupingBy(Transaction::getYear));//collect作为收集器,groupingBy作为分组函数

        Map<Integer,Long> map1 = transactionList.stream().collect(groupingBy(Transaction::getValue,counting()));//分组之后计数

        System.out.println("groupMap:"+map);

        System.out.println("groupCountMap:"+map1);

        //找到额度最小的交易
        Optional<Transaction> minestTransaction = transactionList.stream().min(comparing(Transaction::getValue));

        System.out.println("minestTransaction:"+minestTransaction.get());


        Optional<Transaction> maxTransaction = transactionList.stream()
                .collect(maxBy(comparingInt(Transaction::getValue)));
        System.out.println("maxTransaction:"+maxTransaction);


        //


        //获取所有交易员名词的连接字符串
        String traderStr = transactionList.stream()
                                          .map(transaction -> transaction.getTrader().getName())
                                          .distinct()
                                          .peek(System.out::println)
                                          .sorted()
                                          .collect(joining());

        System.out.println("traderStr:"+traderStr);


        boolean existed = transactionList.stream().map(transaction ->transaction.getTrader().getName()).distinct()
                .anyMatch(name->name.equals("Raoul"));


        System.out.println("existed:"+existed);



        IntSummaryStatistics intSummaryStatistics = transactionList.stream().mapToInt(Transaction::getValue).summaryStatistics();
        System.out.println("intSummaryStatistics:"+intSummaryStatistics);

        int totalValue = transactionList.stream().collect(reducing(0,Transaction::getValue,(i,j)->i+j));
        System.out.println("totalValue:"+totalValue);
    }
}

 以上示例讲解了Stream常见的方法的具体使用方法。

另外,map作为映射,但是一些场景可能需要使用flatMap才能实现,flatMap如同方法名作为平面,将两组流都打散进行计算。以下我们通过一个例子进行讲解,勾股定律大家一定比较熟,那么我们如果写一个方法,如果是用map只能对一个参数做映射,没办法将三角形的三个边进行公示关联。但是flatMap可以的,把两条边的数据分别当做流,然后打散进行公示关联,就可以计算。具体如下:

//勾股定律
    public static Stream<int[]> getTriples(int start,int end,int limit){
        Stream<int[]> pythagoreanTriples = IntStream.rangeClosed(start,end).boxed()
                                                    .flatMap(a->
                                                          IntStream.rangeClosed(a,end)
                                                                   .filter(b->Math.sqrt(a*a+b*b)%1==0)
                                                                  .mapToObj(b->new int[]{a,b,(int)Math.sqrt(a*a+b*b)})).limit(limit);
        return pythagoreanTriples;

    }

3.流的特性

3.1不存储数据

Stream<Integer> iterateStream=Stream.iterate(1,x->x+1);
        //generateStream.limit(100).forEach(x->System.out.println(x));
        iterateStream.limit(10).forEach(System.out::println);
        iterateStream.limit(10).forEach(System.out::println);

执行之后,如以下结果,第二次报错

1
2
3
4
5
6
7
8
9
10
java.lang.IllegalStateException: stream has already been operated upon or closed
	at java.util.stream.AbstractPipeline.<init>(AbstractPipeline.java:203)
	at java.util.stream.ReferencePipeline.<init>(ReferencePipeline.java:94)
	at java.util.stream.ReferencePipeline$StatefulOp.<init>(ReferencePipeline.java:647)
	at java.util.stream.SliceOps$1.<init>(SliceOps.java:120)
	at java.util.stream.SliceOps.makeRef(SliceOps.java:120)
	at java.util.stream.ReferencePipeline.limit(ReferencePipeline.java:401)
	at com.carson.commons.stool.stream.StreamUtil.main(StreamUtil.java:70)

          上述例子可以看出流不具备存储数据的功能,都是一次性的。

 

3.2延迟特性

      Stream在使用collect,forEach等终止方法之前都不会去执行数据输出操作。比如以下示例

Stream<Integer> arrayStream = Stream.of(1,2,4,6,7).filter(x->{
            System.out.println("test_"+x);
            return true;
        });
        System.out.println("check");
        arrayStream.collect(Collectors.toList());

执行输出结果:

check
test_1
test_2
test_4
test_6
test_7

 

4.原始类型流

目录

1.创建流

 1.1.创建空流

1.2.根据数组和集合创建流

1.3.创建无限流

2.流的操作

3.流的特性

3.1不存储数据

3.2延迟特性

4.原始类型流

 


     Stream原始类型流有IntStream、DoubleStream,这个基本类型流都是与Stream一样继承BaseStream的,所以很多特性都是一致的,另外还增加了一些原始类型流的特性。

IntStream stream1 = IntStream.rangeClosed(0,10);
        IntStream stream2 = IntStream.range(0,10);
        stream1.forEach(System.out::println);
        stream2.forEach(System.out::println);

rangeClosed是右区间闭合的,range是右区间不闭合的。

    IntStream->Stream<Integer>是通过boxed()方法进行转换的。

IntStream stream1 = IntStream.rangeClosed(0,10);
        Stream<Integer> stream = stream1.boxed();

Stream->IntStream通过IntStream mapToInt(ToIntFunction<? super T> mapper);进行转换

IntStream stream1 = IntStream.rangeClosed(0,10);
        Stream<Integer> stream = stream1.boxed();
        IntStream stream2 = stream.mapToInt(x->x*x);

以上操作同样适用于DoubleStream。

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值