import org.junit.Test;
import java.text.Collator;
import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class QuestionDemo {

    //1)第一步:把集合转换为流stream
    //2)第二步:操作stream流
    //stream流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果

    // 怎么处理set/list/map集合,流的很多方法:stream.map、
    //stream流学了哪几种方法、要举例说明、学精学透。本周学流
    //如何用流处理父子级的数据结构、如果用流把数据整理出来



      @Test
        public void filter(){
        List<String> filterList= Arrays.asList("abc", "bca","ddf","qwer","pij");
        List<String> containsfilter =filterList.stream().filter(str -> str.contains("a")).collect(Collectors.toList());
        //str是流里面的每个元素,str.contains("a")是如果流中的数据包含a,就把数据放到最新的流中去
        //.collect(Collectors.toList())把流再转化为集合
        System.out.println(containsfilter);
        }


        @Test
        public void distinct(){
            List<String> distinctList= Arrays.asList("abc", "bca","ddf","pij","pij");//list中相同元素的内存地址是一样的
            Collection<String> distinct = distinctList.stream().distinct().collect(Collectors.toList());
            //distinct用来去掉重复的数据
            System.out.println(distinct);
            //-------------------------------------------------------------------------------------------
            List<User> users = new ArrayList<>();
            users.add(new User(1,"z"));//new的对象,存储的地址是不一样的
            users.add(new User(1,"z"));
            users.add(new User(2,"s"));
            Collection<User> distinctusers = users.stream().distinct().collect(Collectors.toList());
            System.out.println(distinctusers);//输出的内容还是三个内容,为啥虽然有两个数据是一样的,但是还是没有去重?因为distinct函数是比较的内存地址
        }

        /*
        Collction:单列集合类的根接口,用于存储一系列符合某种规则的元素,它由两个重要的子接口,分别是List和Set。
        其中List的特点是元素有序、可重复:所有的元素是以一种线性方式存储的,在程序中可以通过索引来访问集合中的指定元素,另外,List集合还有一个特点就是元素**有序**,即元素的存入顺序和取出顺序一致。
        Set的特点是元素无序,而且不可重复。
        List接口的主要实现类有ArrayList和LinkedList。
        ArrayList集合:在ArrayList内部封装了一个长度可变的数组对象,当存入的元素超过数组长度时,ArrayList会在内存中分配一个更大的数组来存储这些元素,因此可以将ArrayList集合看作一个长度可变的数组。
        LinkedList集合:由于ArrayList 集合在查询元素时速度很快,但在增删元素时效率较低。为了克服这种局限性,可以使用List接口的另一个实现类LinkedList。该集合内部维护了一个双向循环链表,链表中的每一个元素都使用引用的方式来记住它的前一个元素和后一个元素,从而可以将所有的元素彼此连接起来。当插入一个新元素时,只需要修改元素之间的这种引用关系即可,删除一个节点也是如此。正因为这样的存储结构,LinkedList集合对于元素的增删操作具有很高的效率。
        Set接口的主要实现类有HashSet和TreeSet

        Map:双列集合类的根接口,用于存储具有键(key)、值(value)映射映射关系的元素,每个元素包含一对键值,
        在使用Map集合时可以通过指定的Key找到对应的Value,Map接口的主要实现类有HashMap和TreeMap。
         */

    @Test
    public void limit(){
        List<String> limitList= Arrays.asList("abc", "bca","ddf","pij","pij");//list中相同元素的内存地址是一样的
        Collection<String> limit = limitList.stream().limit(2).collect(Collectors.toList());
        //limit返回一个给定长度的流,像上面给的参数是2就返回流中前面两个数据
        System.out.println(limit);
    }
    @Test
    public void skip(){
        List<String> skipList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        Collection<String> collect = skipList.stream().skip(3).collect(Collectors.toList());
        //跳过skip参数中的前N个数据,返回后面的数据
        System.out.println(collect);
    }
    @Test
    public void map1(){
        List<String> strings = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        Collection<String> mapped = strings.stream().map(str -> str.concat("_666")).collect(Collectors.toList());//在流元素后面添加一个”_666“组合成为一个新的流
        //map:接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一个新版本”而不是去“修改”)。
        System.out.println(mapped);
    }
    @Test
    public void map2(){
        List<String> strings = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        Collection<String> mapped = strings.stream().map(str -> "123"+str).collect(Collectors.toList());//在流中元素钱面添加一个”123“组合成为一个新的流
        //map:接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一个新版本”而不是去“修改”)。
        System.out.println(mapped);
    }

    @Test
    public void flatmap(){
        List<String> strings = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        List<Character> flatmaped = strings.stream().flatMap(str -> QuestionDemo.getCharacterByString(str)).collect(Collectors.toList());
       //使用flatMap方法的效果是,各个数组并不是分别映射成一个流,而是映射成流的内容。所有使用map(Arrays::stream)时生成的单个流都被合并起来,即扁平化为一个流。
        System.out.println(flatmaped);
    }

    @Test
    public void map2flatmap(){
        List<String> flatMapList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        Stream<Character> objectStream = flatMapList.stream().flatMap(str -> QuestionDemo.getCharacterByString(str));
       //解析:flatmap
        //(1)[s,i,e],[h,u,a,w,e,i],[p,g,3],[i,d,e,a]
        //(2)[s,i,e,h,u,a,w,e,i,p,g,3,i,d,e,a]这就是flatmap扁平化操作
        objectStream.forEach(str -> System.out.println(str));

        List<String> mapList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        Stream<Stream<Character>> streamStream = mapList.stream().map(QuestionDemo::getCharacterByString);
        //(1)[s,i,e],[h,u,a,w,e,i],[p,g,3],[i,d,e,a]   map没有扁平化
        streamStream.forEach(System.out::println);

    }
    /**
     * 功能描述:字符串转换为字符流
     * @param str
     * @return : java.util.stream.Stream<java.lang.Character>
     */
    public static Stream<Character> getCharacterByString(String str) {
        List<Character> characterList = new ArrayList<>();
        for (Character character : str.toCharArray()) {
            characterList.add(character);
        }
        return characterList.stream();
    }

    @Test
    public void sorted(){
        //-------------------英文字符串排序:按24字母的前后顺序来排序------------------------
        List<String> englishList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        List<String> sorted1 = englishList.stream().sorted().collect(Collectors.toList());
        System.out.println(sorted1);
        //-------------------中文排序:按拼音来排序,需要导入comparator,可倒序可顺序-。其中Collections.reverseOrder是倒序-----------------------
        List<String> chinese1List = Arrays.asList("红茶", "绿观音", "大红袍", "咖啡");
        List<String> sorted2 = chinese1List.stream().sorted(Collections.reverseOrder(Collator.getInstance(Locale.CHINA))).collect(Collectors.toList());
        System.out.println(sorted2);
        //--------------------中文排序:没有使用Collections.reverseOrder就是顺序
        List<String> chinese2 = Arrays.asList("红茶", "绿观音", "大红袍", "咖啡");
        List<String> sorted3 = chinese2.stream().sorted(Collator.getInstance(Locale.CHINA)).collect(Collectors.toList());
        System.out.println(sorted3);
    }
    /**
     * 终止符:满足条件就返回值,不用在for里面去写if
     */
        @Test
    public void anyMatch(){
            List<String> anymatchList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
            boolean any1 = anymatchList.stream().anyMatch(str -> str.contains("g"));
            //集合中是否有一个元素满足条件
            System.out.println(any1);
        }
         @Test
    public void allMatch(){
        List<String> anymatchList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        boolean all1 = anymatchList.stream().allMatch(str -> str.length()>3);
        //集合中是否所有的元素都满足条件
        System.out.println(all1);
    }
    @Test
    public void noneMatch(){//集合中所有元素都不满足条件
        List<String> noneMatchList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        boolean none1 = noneMatchList.stream().noneMatch(str -> str.length()>6);//没有长度大于6的元素,属于所有的元素都不满足条件,即返回true
        System.out.println(none1);
    }
    @Test
    public void findAny(){//将返回当前流中的任意元素,虽然说他是随机返回流中的一个元素,但是他默认是返回第一个元素。
        List<String> findAnyList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        Optional<String> any = findAnyList.stream().findAny();
        System.out.println(any);
    }

    @Test
    public void findAny2(){
        List<String> findAnyList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        for (int i = 0; i < 10000 ;i++){
            Optional<String> any= findAnyList.parallelStream().findAny();
            //用parallelStream来证明一下findAny并不是只拿第一个,parallelStream是并行的,所以随机取数取到不同的概率大
            if(any.isPresent()) System.out.println(any.get());
        }
    }

    @Test
    public void findFirst(){//将返回当前流中的第一个元素
        List<String> findFirstList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        Optional<String> find = findFirstList.stream().findFirst();
        System.out.println(find);
    }
    @Test
    public void foreach(){//遍历输出流中的数据
        List<String> foreachList = Arrays.asList("sex", "hhhhh", "ppt", "idea");
        foreachList.stream().forEach(System.out::println);//forEach(s -> sout(s));
    }

    @Test
    public void collect(){//将流转换成其他形式:list、map、set
            //例如转一个set,set是一个无序不重复的,list转成set砍掉了相同的数据
        List<String> collect = Arrays.asList("sex", "hhhhh", "ppt", "idea","idea");
        Set<String> toset = collect.stream().collect(Collectors.toSet());
        System.out.println(toset);
    }



    @Test
    public void collect2(){//将流转换成其他形式:list、map、set
        //转map
        List<String> collect2 = Arrays.asList("sex", "hhhhh", "ppt", "idea","idea");
        Map<String,String> map = collect2.stream().collect(Collectors.toMap(v ->v.concat("_name"), v1 -> v1, (v1, v2) -> v1));
        System.out.println(map);
    }

    @Test
    public  void test() {
        List<String> testlist = new ArrayList<>();


        System.out.println(testlist);

        }

}