JDK 1.8 针对集合操作的Stream

Stream API

Stream操作的三个步骤

创建stream
中间操作(过滤、map)
终止操作

stream的创建:

//创建Stream
@Test
public void test1(){
    //1.可以通过Collection系列集合提供的Stream()或parallelStream
    List list=new ArrayList();
    Stream stream=  list.stream();
    //2.通过Arrays的静态方法stream获取数组流
    Student[] students=new Student[10];
    Stream stream2=Arrays.stream(students);
    //3.通过Stream中的of()静态方法也可以获取流
    Stream stream3=Stream.of("aa","bb","cc");
    //4.创建无限流
    //迭代
    Stream stream4=Stream.iterate(0, (x)->x+2);
    stream4.limit(10).forEach(System.out::println);
    //生成
    Stream.generate(()-> new Random().nextInt(100)).limit(10).forEach(System.out::println);

}

中间操作:sorted ,map ,filter

List students=Arrays.asList(
        new Student("张三", 23),
        new Student("李四", 38),
        new Student("王五", 55),
        new Student("赵六", 18),
        new Student("田七", 29),
        new Student("田七", 29),
        new Student("田七", 29));
//中间操作
/**
 * 排序
 * sorted()——自然排序(Comparable)
 * sorted(Comparator com)——定制排序(Comparator)
 */

@Test
public void test5() {
    List list=Arrays.asList("aaa","bbb","ccc","ddd","eee");
    list.stream()
    .sorted()
    .forEach(System.out::println);
    System.out.println("----------------------");
    students.stream()
    .sorted((s1,s2)->{
        if(s1.getAge().equals(s2.getAge())){
            return s1.getName().compareTo(s2.getName());
        }else{
            return -s1.getAge().compareTo(s2.getAge());
        }
    })
    .forEach(System.out::println);
    }

/**
 * 映射
 * map——接受lambda ,将元素转换成其他形式或提取信息。接受一个函数作为参数,该
 *      函数会被应用到每个元素上,并将其映射成一个新的元素
 * flatMap——接受一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有流连接成一个流
 */
@Test
public void test4() {
    List list=Arrays.asList("aaa","bbb","ccc","ddd","eee");
    //流操作
    list.stream()
    .map((str)->str.toUpperCase())
    .forEach(System.out::println);
    System.out.println("----------------------");
    students.stream()
    .map(Student::getName)
    .forEach(System.out::println);
    System.out.println("----------------------");
    Stream> stream=list.stream()
            .map(TestStreamApi2::filterCharacter);
    stream.forEach((sm)->{
        sm.forEach(System.out::println);
    });
    System.out.println("----------------------");
    Stream stream2=  list.stream()
    .flatMap(TestStreamApi2::filterCharacter);
    stream2.forEach(System.out::println);
}



public static Stream filterCharacter(String str) {
    List list=new ArrayList();
    for (Character ch : str.toCharArray()) {
        list.add(ch);
    }
    return list.stream();
}



/**
 * 筛选与切片
 * filter——接受lambda ,从流中排除某些元素
 * limit—— 阶段流,使其不超过指定数量
 * skip(n)—— 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit互补
 * distinct——筛选,通过硫所生成元素的hashCode()和equals去除重复元素
 * 
 */
@Test
public void test3() {
students.stream()
    .filter((s)->{
        System.out.println("短路!");
        return s.getAge()>25;
    })
    .skip(2)
    .distinct()
    .forEach(System.out::println);
}




@Test
public void test2() {
students.stream()
    .filter((s)->{
        System.out.println("短路!");
        return s.getAge()>25;
    })
    .limit(2)
    .forEach(System.out::println);
}





//内部迭代:迭代操作有Stream API完成
@Test
public void test1() {
    //1.获取流
    Stream stream=students.stream()
     //2.中间操作:不会执行任何操作
    .filter((s)->{
        System.out.println("StreamAPI的中间操作!");
        return s.getAge()>35;
    });
    //3.终止操作:一次性执行全部的内容,"即惰性求值"
    stream.forEach(System.out::println);

}

终止操作:

public class TestStreamApi3 {
List students=Arrays.asList(
new Student(“张三”, 23,5555,Status.BUSY),
new Student(“李四”, 38,6666,Status.FREE),
new Student(“王五”, 55,8888,Status.VOCATION),
new Student(“赵六”, 18,7777,Status.FREE),
new Student(“田七”, 29,9999,Status.BUSY),
new Student(“田七”, 29,9999,Status.BUSY));
/**
 * 收集
 * collect——将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
 */
 @Test
public void test10() {
    String str= students.stream()
             .map(Student::getName)
             .collect(Collectors.joining(","));
    System.out.println(str);

 }


 @Test
public void test9() {
DoubleSummaryStatistics dss= students.stream()
             .collect(Collectors.summarizingDouble(Student::getSalary));
System.out.println(dss.getAverage());
System.out.println(dss.getMax());
System.out.println(dss.getCount());
System.out.println(dss.getSum());


 }


//分区
 @Test
    public void test8() {
     Map> map=students.stream().collect(Collectors.partitioningBy((s)-> s.getSalary()>7000));
     System.out.println(map);
 }



//多级分组
 @Test
    public void test7() {
     Map>> map= students.stream()
             .collect(Collectors.groupingBy(Student::getStatus, Collectors.groupingByConcurrent((s)->{
                 if(((Student)s).getAge()<=35){
                     return "青年";
                 }else if(((Student)s).getAge()<=50){
                     return "中年";
                 }else{
                     return "老年";
                 }
             })));
     System.out.println(map);
 }


//分组
 @Test
    public void test6() {
     Map>  map= students.stream()
             .collect(Collectors.groupingBy(Student::getStatus));
     System.out.println(map);
 }

 @Test
    public void test5() {
     //总数
    long count=students.stream().collect(Collectors.counting());
    System.out.println(count);
     System.out.println("-------------------------------");
    //平均值
    Double avg=students.stream().collect(Collectors.averagingDouble(Student::getSalary));
    System.out.println(avg);
     System.out.println("-------------------------------");
     //总和
     Double sum= students.stream().collect(Collectors.summingDouble(Student::getSalary));
     System.out.println(sum);
     System.out.println("-------------------------------");
     //最大值
     Optional optional=students.stream()
             .collect(Collectors.maxBy((s1,s2)-> Integer.compare(s1.getSalary(), s2.getSalary())));
     System.out.println(optional.get());
     //最小值
     Optional optional2= students.stream()
             .map(Student::getSalary)
             .collect(Collectors.minBy(Integer::compare));
     System.out.println(optional2.get());

 }



 @Test
    public void test4() {
     List names= students.stream()
     .map(Student::getName)
     .collect(Collectors.toList());
     names.forEach(System.out::println);
     System.out.println("-------------------------------");
     Set set= students.stream()
             .map(Student::getName)
             .collect(Collectors.toSet());
     set.forEach(System.out::println);
     System.out.println("-------------------------------");
     HashSet set2= students.stream()
             .map(Student::getName)
             .collect(Collectors.toCollection(HashSet::new));
     set2.forEach(System.out::println);
 }

/**
 * 归约
 * reduce(T identity,BinaryOperator ) /reduce(BinaryOperator)——可以将流中元素反复结合起来,得到一个值
 */
 @Test
    public void test3() {
     List list=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
     Integer  sum= list.stream().reduce(0, (x,y)->x+y);
     System.out.println(sum);
     System.out.println("-------------------------------");
     Optional optional  = students.stream().map(Student::getSalary).reduce(Integer::sum);
     System.out.println(optional.get());
 }



/**
 * 查找与匹配
 * allMatch——检查是否匹配所有元素
 * anyMatch——检查是否至少匹配一个元素
 * noneMatch——检查是否没有匹配所有元素
 * findFoirst——返回第一个元素
 * findAny——返回流中的任意元素
 * count——返回流中元素的总个数
 * max——返回流中元素的最大值
 * min——返回流中元素的最小值
 */
//统计相关
 @Test
    public void test2() {
    Long long1= students.stream().count();
    System.out.println(long1);

    Optional optional=students.stream()
            .max((s1,s2)->Integer.compare(s1.getSalary(), s2.getSalary()));
    System.out.println(optional.get());

    Optional optional2=    students.stream()
    .map(Student::getAge)
    .min(Integer::compare);
    System.out.println(optional2.get());

 }


@Test
public void test1() {
    boolean b=  students.stream().allMatch((s)->s.getStatus().equals(Status.BUSY));
    System.out.println(b);
    System.out.println("-----------------------------------");
    boolean b2=students.stream().anyMatch((s)->s.getStatus().equals(Status.BUSY));
    System.out.println(b2);
    System.out.println("-----------------------------------");
    boolean b3=students.stream().noneMatch((s)->s.getStatus().equals(Status.BUSY));
    System.out.println(b3);
    System.out.println("-----------------------------------");
    //按工资排序,并返回第一个
    Optional opt=students.stream().sorted((s1,s2)->{
        return -s1.getSalary().compareTo(s2.getSalary());
    }).findFirst();
    System.out.println(opt.get());
    System.out.println("-----------------------------------");
    //找一个空闲的人
    Optional opt2=students.parallelStream()
     .filter((s)->s.getStatus().equals(Status.FREE))
     .findAny();
    System.out.println(opt2.get());
}

并行流和串行流

在jdk1.8新的stream包中针对集合的操作也提供了并行操作流和串行操作流。并行流就是把内容切割成多个数据块,并且使用多个线程分别处理每个数据块的内容。Stream api中声明可以通过parallel()与sequential()方法在并行流和串行流之间进行切换。
jdk1.8并行流使用的是fork/join框架进行并行操作
ForkJoin框架

Fork/Join 框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总。
关键字:递归分合、分而治之。
采用 “工作窃取”模式(work-stealing):
当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线
程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中
相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的
处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因
无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果
某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子
问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程
的等待时间,提高了性能.。

/**
 * 要想使用Fark—Join,类必须继承
 * RecursiveAction(无返回值)
 * Or
 * RecursiveTask(有返回值)
*
*/
public class ForkJoin extends RecursiveTask {

    /**
     * 要想使用Fark—Join,类必须继承RecursiveAction(无返回值) 或者
     * RecursiveTask(有返回值)
     *
     * @author Wuyouxin
     */
    private static final long serialVersionUID = 23423422L;

    private long start;
    private long end;

    public ForkJoin() {
    }

    public ForkJoin(long start, long end) {
        this.start = start;
        this.end = end;
    }

    // 定义阙值
    private static final long THRESHOLD = 10000L;

    @Override
    protected Long compute() {
        if (end - start <= THRESHOLD) {
            long sum = 0;
            for (long i = start; i < end; i++) {
                sum += i;
            }
            return sum;
        } else {
            long middle = (end - start) / 2;
            ForkJoin left = new ForkJoin(start, middle);
            //拆分子任务,压入线程队列
            left.fork();
            ForkJoin right = new ForkJoin(middle + 1, end);
            right.fork();

            //合并并返回
            return left.join() + right.join();
        }
    }

    /**
     * 实现数的累加
     */
    @Test
    public void test1() {
        //开始时间
        Instant start = Instant.now();

        //这里需要一个线程池的支持
        ForkJoinPool pool = new ForkJoinPool();

        ForkJoinTask task = new ForkJoin(0L, 10000000000L);
        // 没有返回值     pool.execute();
        // 有返回值
        long sum = pool.invoke(task);

        //结束时间
        Instant end = Instant.now();
        System.out.println(Duration.between(start, end).getSeconds());
    }

    /**
     * java8 并行流 parallel()
     */
    @Test
    public void test2() {
        //开始时间
        Instant start = Instant.now();

        // 并行流计算    累加求和
        LongStream.rangeClosed(0, 10000000000L).parallel()
                .reduce(0, Long :: sum);

        //结束时间
        Instant end = Instant.now();
        System.out.println(Duration.between(start, end).getSeconds());
    }

    @Test
    public void test3(){
        List list = Arrays.asList(1, 2, 3, 4, 5);
        list.stream().forEach(System.out::print);

        list.parallelStream()
            .forEach(System.out::print);
    }

Optional容器

使用Optional容器可以快速的定位NPE,并且在一定程度上可以减少对参数非空检验的代码量。

/**
     *      Optional.of(T t); // 创建一个Optional实例
     *      Optional.empty(); // 创建一个空的Optional实例
     *      Optional.ofNullable(T t); // 若T不为null,创建一个Optional实例,否则创建一个空实例
     *      isPresent();    // 判断是够包含值
     *      orElse(T t);   //如果调用对象包含值,返回该值,否则返回T
     *      orElseGet(Supplier s);  // 如果调用对象包含值,返回该值,否则返回s中获取的值
     *      map(Function f): // 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty();
     *      flatMap(Function mapper);// 与map类似。返回值是Optional
     *
     *      总结:Optional.of(null)  会直接报NPE
     */

Optional op = Optional.of(new Employee("zhansan", 11, 12.32, Employee.Status.BUSY));
        System.out.println(op.get());

        // NPE
        Optional op2 = Optional.of(null);
        System.out.println(op2);
@Test
    public void test2(){
        Optional op = Optional.empty();
        System.out.println(op);

        // No value present
        System.out.println(op.get());
    }
@Test
    public void test3(){
        Optional op = Optional.ofNullable(new Employee("lisi", 33, 131.42, Employee.Status.FREE));
        System.out.println(op.get());

        Optional op2 = Optional.ofNullable(null);
        System.out.println(op2);
       // System.out.println(op2.get());
    }
    @Test
    public void test5(){
        Optional op1 = Optional.ofNullable(new Employee("张三", 11, 11.33, Employee.Status.VOCATION));
        System.out.println(op1.orElse(new Employee()));
        System.out.println(op1.orElse(null));
    }

    @Test
    public void test6(){
        Optional op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));
        op1 = Optional.empty();
        Employee employee = op1.orElseGet(() -> new Employee());
        System.out.println(employee);
    }

    @Test
    public void test7(){
        Optional op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));
        System.out.println(op1.map( (e) -> e.getSalary()).get());
    }
 
  

实例应用:


1.利用Google的  import com.google.common.collect.Lists; 
   代码:
 public void listToList(){
    //源list
    List listResults = Lists.newArrayList(new Result(1,"test1"),new Result(2,"test2"),new Result(3,"test3"));
    //转换为目标list
    List strLists = Lists.transform(listResults,new Function(){
      @Override
      public String apply(Result result){
        return result.getNameStr();
      }
    });
  }


2.lamada表达式

要提取属性的话,用Stream中的map,然后使用方法引用,就可以了。

举个例子Student类中有name属性:

List students = new ArrayList();

List names =students.stream().map(Student::getName).collect(Collectors.toList());


3. 集合 转化为 集合

 List students = persons.stream().map(person -> {
            Student student = new Student();
            BeanUtils.copyProperties(person, student);
            if (person.getName() == "张三") {
                student.setSchoolName("三中");
                student.setsId(3L);
            }
            if (person.getName() == "李四") {
                student.setSchoolName("四中");
                student.setsId(4L);
            }
            return student;
        }).collect(Collectors.toList());
        System.out.println("students = " + students);

    }


对集合进行排序:
@Test
public void whenSortingEntitiesByName_thenCorrectlySorted() {
List humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
 
humans.sort((Human h1, Human h2) -> h1.getName().compareTo(h2.getName()));
Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}


//解释:
Collections.sort(plist, new Comparator(){
            /*
             * int compare(Person p1, Person p2) 返回一个基本类型的整型,
             * 返回负数表示:p1 小于p2,
             * 返回0 表示:p1和p2相等,
             * 返回正数表示:p1大于p2
             */
            public int compare(Person p1, Person p2) {
                //按照Person的年龄进行升序排列
                if(p1.getAge() > p2.getAge()){
                    return 1;
                }
                if(p1.getAge() == p2.getAge()){
                    return 0;
                }
                return -1;
            }
        });
        System.out.println("排序后的结果:"+plist);  










你可能感兴趣的:(jdk1.8新特性)