zoukankan      html  css  js  c++  java
  • Java流(Stream)操作实例-筛选、映射、查找匹配

    准备工作

    构建一个测试类,通过测试类先初始化一个数据源,具体如下。

    public class TestObject {
    	private String name;
    	private String sex;
    	private int age;
    	private String email;
    	private boolean isMng;
    	
    	public TestObject() {
    	}
    	
    	public TestObject(String name,String sex,int age,String email,boolean isMng){
    		this.name=name;
    		this.sex=sex;
    		this.age=age;
    		this.email=email;
    		this.isMng=isMng;
    	}
    //... ...get、set方法就不贴出来了,多又麻烦
    }
    
    

    在测试类中定义初始化数据源

    public class StreamOperation {
    	static List<TestObject> list = Arrays.asList(
    			new TestObject("Ron","M",10,"ron.zheng@tfschange.com",false),
    			new TestObject("KDS","W",10,"kds@qq.com",false),
    			new TestObject("BoDuo","W",30,"boduo@163.com",false),
    			new TestObject("CangJin","W",10,"cangjin@gmail.com",false),
    			new TestObject("XiaoZe","W",30,"xiaoze@hotmail.com",true),
    			new TestObject("James","M",10,"leblonjames@hotmail.com",true),
    			new TestObject("Allen","M",50,"allen.lei@tfschange.com",true),
    			new TestObject("Smith","M",10,"jr.smith@cel.com",true),
    			new TestObject("Wade","M",20,"dw.wade@cel.com",true),
       new TestObject("Wade","M",20,"dw.wade@cel.com",false)
    			);
    }
    
    
    

    用谓词筛选

    Streams接口支持filter方法,该操作会接受一个谓词(一个返回boolean的函数)作为参数,并返回一个包括所有符合谓词的元素的流。比如我们需要筛选isMng为ture的数据并打印名字就可以按照如下的方式处理。

    /**
    	 * @Comment 获取Leader
    	 * @Author Ron
    	 * @Date 2017年11月24日 下午2:01:16
    	 * @return
    	 */
    	public static List<TestObject> getLeader() {
    		return list.stream().filter(TestObject::isMng).collect(Collectors.toList());
    	}
    	
    	public static void main(String[] args) {
    		List<TestObject> leaders = getLeader();
    		leaders.stream().forEach(leader->System.out.println(leader.getName()));
    	}
    
    

    筛选各异的元素

    流还支持一个叫作distinct的方法,它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流。例如,以下代码会筛选出列表中所有的偶数,并确保没有重复。

    public static void main(String[] args) {
    		List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
    		numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);
    	}
    
    

    截短流

    流支持limit(n)方法,该方法会返回一个不超过给定长度的流。所需的长度作为参数传递给limit。如果流是有序的,则最多会返回前n个元素。比如选出前5个sex为M的对象并打印其名称可以按如下的代码操作。

    list.stream().filter(u->u.getSex().equals("M")).limit(5).forEach(u->System.out.println(u.getName()));
    
    

    如果我们需要选出前5个sex为M的对象并按照名称排序之后打印其名称可以按如下的代码操作。

    list.stream()
    		.filter(u->u.getSex().equals("M"))
    		.limit(5)
    		.sorted(Comparator.comparing(TestObject::getName))
    		.forEach(u->System.out.println(u.getName()));
    
    

    跳过元素

    流还支持skip(n)方法,返回一个扔掉了前n个元素的流。如果流中元素不足n个,则返回一个空流。请注意, limit(n)和skip(n)是互补的。例如,下面的代码将会跳过筛选出来的第一个元素并打印名字。

    list.stream()
    		.filter(u->u.getSex().equals("M"))
    		.sorted(Comparator.comparing(TestObject::getName))
    		.skip(1)
    		.forEach(u->System.out.println(u.getName()));
    
    

    对流中每一个元素应用函数

    流支持map方法,它会接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一个新版本”而不是去“修改”)。例如,下面的代码把方法引用TestObject::getName传给了map方法,来提取流中用户的名称并打印:

    list.stream()
    .map(TestObject::getName)
    .collect(Collectors.toList())
    .forEach(System.out::println);
    
    

    因为getName方法返回一个String,所以map方法输出的流的类型就是Stream⁢String>。

    我们来再看一个例子,我们把方法引用TestObject::getName传给了map方法,来提取流中用户的名称,然后再打印用户名称的长度。你可以像下面这样,给map传递一个方法引用String::length来解决这个问题:

    list.stream()
    		.map(TestObject::getName)
    		.map(String::length)
    		.collect(Collectors.toList())
    		.forEach(System.out::println);
    
    

    检查谓词是否至少匹配一个元素

    anyMatch方法可以回答“流中是否有一个元素能匹配给定的谓词”。比如,你可以用它来看看用户列表里面是否有名称为Ron的对象可选择:

    if(list.stream().anyMatch(u->u.getName().equals("Ron"))){
    		System.out.println("Ron已经到了");
    	}
    
    

    anyMatch方法返回一个boolean,因此是一个终端操作。

    检查谓词是否匹配所有元素

    allMatch方法的工作原理和anyMatch类似,但它会看看流中的元素是否都能匹配给定的谓词。比如,你可以用它来看看用户是否都大于10岁。

    if(list.stream().allMatch(u->u.getAge()>=10)){
    		System.out.println("很棒,都大于10岁");
    	}else{
    		System.out.println("原来都还没发育");
    	}
    
    

    和allMatch相对的是noneMatch。它可以确保流中没有任何元素与给定的谓词匹配。比如,你可以用noneMatch重写前面的例子:

    if(list.stream().noneMatch(u->u.getAge()<10)){
    		System.out.println("很棒,都大于10岁");
    	}else{
    		System.out.println("原来都还没发育");
    	}
    
    

    anyMatch、 allMatch和noneMatch这三个操作都用到了我们所谓的短路,这就是大家熟悉的Java中&&和||运算符短路在流中的版本。

    Optional简介

    Optional类(java.util.Optional)是一个容器类,代表一个值存在或不存在。Java 8的库设计人员引入了Optional,这样就不用返回众所周知容易出问题的null了。Optional里面几种可以迫使你显式地检查值是否存在或处理值不存在的情形。

    isPresent()将在Optional包含值的时候返回true, 否则返回false。
    ifPresent(Consumer block)会在值存在的时候执行给定的代码块。
    T get()会在值存在时返回值,否则抛出一个NoSuchElement异常。
    T orElse(T other)会在值存在时返回值,否则返回一个默认值。
    查找元素

    findAny方法将返回当前流中的任意元素。它可以与其他流操作结合使用。

    例如,我们需要显示的检查是否存在一个名为‘Ron’的人并显示其名称就可以按照如下的代码操作。

    list.stream()
    		.filter(u->u.getName().equals("Ron"))
    		.findAny()
    		.ifPresent(u->System.out.println(u.getName()));
    
    

    流水线将在后台进行优化使其只需走一遍,并在利用短路找到结果时立即结束。

    查找第一个元素

    有些流有一个出现顺序(encounter order)来指定流中项目出现的逻辑顺序(比如由List或排序好的数据列生成的流)。对于这种流,你可能想要找到第一个元素。为此有一个findFirst方法,它的工作方式类似于findany。

    例如我们需要找到第一个isLeader为ture的对象并打印其名字,就可以按照如下的代码操作。

    list.stream()
    		.filter(u->u.isLeader())
    		.findFirst()
    		.ifPresent(u->System.out.println(u.getName()));
    
    

    何时使用findFirst和findAny

    你可能会想,为什么会同时有findFirst和findAny呢?答案是并行。找到第一个元素在并行上限制更多。如果你不关心返回的元素是哪个,请使用findAny,因为它在使用并行流时限制较少。

    将数据收集进一个列表(Stream 转换为 List,允许重复值,有顺序)

    //1.将数据收集进一个列表(Stream 转换为 List,允许重复值,有顺序)
    //创建流
    Stream<String> language = Stream.of("java", "python", "C++","php","java");
    List<String> listResult = language.collect(Collectors.toList());
    result.forEach(System.out::println);
    
    

    Set

    Set<String> setResult = language.collect(Collectors.toSet());
    
    

    用自定义的实现Collection的数据结构收集

    List<String> list = Arrays.asList("java", "python", "C++","php","java");  
          //用LinkedList收集
          List<String> linkedListResult = list.stream().collect(Collectors.toCollection(LinkedList::new));
          linkedListResult.forEach(System.out::println);
          System.out.println("--------------");
          
          //用CopyOnWriteArrayList收集
          List<String> copyOnWriteArrayListResult = list.stream().collect(Collectors.toCollection(CopyOnWriteArrayList::new));
          copyOnWriteArrayListResult.forEach(System.out::println);
          System.out.println("--------------");
          
          //用TreeSet收集
          TreeSet<String> treeSetResult = list.stream().collect(Collectors.toCollection(TreeSet::new));
          treeSetResult.forEach(System.out::println);
    
    

    对Stream的字符串拼接

      List<String> list = Arrays.asList("java", "python", "C++","php","java");
    	    //直接将输出结果拼接
            System.out.println(list.stream().collect(Collectors.joining()));
            //每个输出结果之间加拼接符号“|”
            System.out.println(list.stream().collect(Collectors.joining(" | ")));
            //输出结果开始头为Start--,结尾为--End,中间用拼接符号“||”
            System.out.println(list.stream().collect(Collectors.joining(" || ", "Start--", "--End")));
    
    

    由一个list转化成另一个list

            // 利用stream进行类型转化
            List<String> stringList = new ArrayList<>();
            stringList.add("a11");
            stringList.add("b11");
            stringList.add("c11");
            stringList.add("d11");
            stringList.add("e11");
            List<Map<String,String>> stringList1 = stringList.stream().map(item->
                    {
                        Map<String,String> map = new HashMap<>();
                        map.put("name", item.toUpperCase());
                        return map;
                    }
            ).collect(Collectors.toList());
    
    

    提取某一列(以name为例)

    List<String> nameList = studentList.stream().map(StudentInfo::getName).collect(Collectors.toList());
    //提取后输出name
    nameList.forEach(s-> System.out.println(s));
    

    提取age列并排重(使用distinct()函数)

    //从对象列表中提取age并排重
    List<Integer> ageList = studentList.stream().map(StudentInfo::getAge).distinct().collect(Collectors.toList());
    ageList.forEach(a-> System.out.println(a));
    
  • 相关阅读:
    iSCSI又称为IPSAN
    文档类型定义DTD
    HDU 2971 Tower
    HDU 1588 Gauss Fibonacci
    URAL 1005 Stone Pile
    URAL 1003 Parity
    URAL 1002 Phone Numbers
    URAL 1007 Code Words
    HDU 3306 Another kind of Fibonacci
    FZU 1683 纪念SlingShot
  • 原文地址:https://www.cnblogs.com/junhe/p/15386919.html
Copyright © 2011-2022 走看看