JDK8 Stream测试

如何创建一个流Stream,三种方法:测试

1、通过 java.util.Collection.stream()

2、通过数组来创建流

3、静态方法:使用Stream的静态方法:of()、iterate()、generate()

public class StreamJ {
    public static void main(String[] args){
//        getOfStream();
        getDusk();

    }
    public void anyMatch(){
        List<String> strings = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
        boolean b = strings.stream().anyMatch(s -> s == "abc");
        System.out.println(b);
    }
    //创建一个空流
    public static void getDusk(){
        Stream<String> ao=Stream.empty();
        //创建无限流,通过limit提取指定大小
        //随机产生20个数字,是生成一个随机的int值,该值介于[0,n)的区间,也就是0到n之间的随机int值,包含0而不包含n
        Stream.generate(()->"number"+new Random().nextInt()).limit(20).forEach(System.out::println);
        //创建20个Student
        Stream.generate(()->new Student("name",10)).limit(20).forEach(System.out::println);
    }
    //通过 java.util.Collection.stream() 方法用集合创建流
    public static void getStream(){
        List<String> sl= Arrays.asList("a","b","c","d");
        //创建一个顺序流
        Stream<String> sortD=sl.stream();
        //创建一个并行流
        Stream<String> parallelStream=sl.parallelStream();
    }
    //通过数组来创建流
    public static void getArrayStream(){
        int[] arr={1,2,3,4,5};
        IntStream inStream= Arrays.stream(arr);
    }
    //使用Stream的静态方法:of()、iterate()、generate()
    public static void getOfStream(){
        Stream<Integer> instream=Stream.of(1,2,3,4,5);
        //指定一个常量seed,生成从seed到常量f的流(1,2,3,4,5)
        Stream<Integer> insreamt=Stream.iterate(0,(a)->a+1).limit(6);
        insreamt.forEach(System.out::println);

        //一下俩种写法输出是一样的UnaryOperator.identity()是Java8的一元运算符,输入是什么,输出就是什么
        Stream.iterate(0,x->x).limit(10).forEach(System.out::println);
        Stream.iterate(0, UnaryOperator.identity()).limit(10).forEach(System.out::println);
        
//下面是对循环的写法
        Stream.iterate(0,(a)->a+1).limit(6).forEach(a->{
                System.out.print(a +"\n");
        });

        Stream<Double> dStream=Stream.generate(Math::random).limit(5);
        dStream.forEach(System.out::println);

        //以上代码等同于
        DoubleStream intStream = DoubleStream.generate(()
                -> { return (int)(Math.random()); });
        intStream.limit(5).forEach(System.out::println);
         
    }
   
    static class Student{
        private String name;
        private int age;

        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getName() {
            return name;
        }

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

以下几点需要注意:

lambda表达式的一种简写,这种简写的学名叫eta-conversion或者叫η-conversion
 把 x -> System.out.println(x) 简化为 System.out::println 的过程称之为 eta-conversion

把 System.out::println 简化为 x -> System.out.println(x) 的过程称之为 eta-expansion

范式:
类名::方法名
方法调用
person -> person.getAge();
可以替换成
Person::getAge

x -> System.out.println(x)
可以替换成
System.out::println
out是一个PrintStream类的对象,println是该类的方法,依据x的类型来重载方法

创建对象
() -> new ArrayList<>();
可以替换为
ArrayList::new
new关键字实际上调用的是ArrayList的构造方法

 

//描述:一元运算,接受一个T类型参数,输出一个与入参一模一样的值
System.out.println(UnaryOperator.identity().apply(10));     // 10
System.out.println(UnaryOperator.identity().apply(10.01));  // 10.01
System.out.println(UnaryOperator.identity().apply(false));  // false
System.out.println(UnaryOperator.identity().apply("10"));   // 10

UnaryOperator<Integer> b = x->x.intValue();  // lambda表达式,这样就只能输入Integer类型了

System.out.println(b.apply(10));

流多种形式:

//创建普通流
Stream<String> stream  = strs.stream();
//创建并行流
Stream<String> stream1 = strs.parallelStream();
//创建一个空的stream
Stream<Integer> stream  = Stream.empty();
//创建无限流,通过limit提取指定大小
Stream.generate(()->"number"+new Random().nextInt()).limit(100).forEach(System.out::println);
Stream.generate(()->new Student("name",10)).limit(20).forEach(System.out::println);



Stream.iterate(0,x->x+1).limit(10).forEach(System.out::println);
Stream.iterate(0,x->x).limit(10).forEach(System.out::println);
//Stream.iterate(0,x->x).limit(10).forEach(System.out::println);与如下代码意思是一样的
Stream.iterate(0, UnaryOperator.identity()).limit(10).forEach(System.out::println);

基本数值型流: 

  1. IntStream
  2. LongStream
  3. DoubleStream

  当然我们也可以用 Stream<Integer>、Stream<Long> >、Stream<Double>,但是 boxing 和 unboxing 会很耗时,所以特别为这三种基本数值型提供了对应的 Stream。

基本数值型流:

IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
IntStream.range(1, 3).forEach(System.out::println);
IntStream.rangeClosed(1, 3).forEach(System.out::println);

流转换为其它数据结构 :

// 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();

常见操作分类:

当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各类操作了。常见的操作可以归类如下。注意:这些中间操作是惰性求值的,也就是说,只有在终止操作被调用时才开始执行。这种方式可以大大减少操作的开销,使得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

 实例:

1)filter

/**
* 功能描述:根据条件过滤集合数据
* @return : void
*/
@Test
public void filter(){
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);
}
2)distinct

/**
* 功能描述:去除集合中重复数据
* @return : void
*/
@Test
public void distinct(){
List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
List<String> distincted = strings.stream().distinct().collect(Collectors.toList());
System.out.println(distincted);
}
3)limit

/**
* 功能描述:指定获取集合前x条数据,重新构造一个新的集合
* @return : void
*/
@Test
public void limit(){
List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
List<String> limited = strings.stream().limit(3).collect(Collectors.toList());
System.out.println(limited);
}
4)skip

/**
* 功能描述:排除集合前x条数据,把后面的数据重新构造一个新的集合
* @return : void
*/
@Test
public void skip(){
List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
List<String> skiped = strings.stream().skip(3).collect(Collectors.toList());
System.out.println(skiped);
}
5)map

/**
* 功能描述:对集合中所有元素统一处理
* @return : void
*/
@Test
public void map(){
List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
List<String> mapped = strings.stream().map(str->str+"-itcast").collect(Collectors.toList());
System.out.println(mapped);
}
6)flatMap

/**
* 功能描述:对集合中所有元素统一处理
* @return : void
*/
@Test
public void flatMap(){
List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
Stream<String> stringStream = strings.stream().map(x -> x);
Stream<String> stringStream1 = strings.stream().flatMap(x -> Arrays.asList(x.split(" ")).stream());
}
7)sorted

/**
* 功能描述 : 对集合进行排序
* @return : void
*/
@Test
public void sorted(){
List<String> strings1 = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
List<String> strings2 = Arrays.asList("张三", "李四", "王五", "赵柳", "张哥","李哥", "王哥");
List<Integer> strings3 = Arrays.asList(10, 2, 30, 22, 1,0, -9);
List<String> sorted1 = strings1.stream().sorted().collect(Collectors.toList());
List<String> sorted2 = strings2.stream().sorted(Collections.reverseOrder(Collator.getInstance(Locale.CHINA))).collect(Collectors.toList());
List<Integer> sorted3 = strings3.stream().sorted().collect(Collectors.toList());
System.out.println(sorted1);
System.out.println(sorted2);
System.out.println(sorted3);
}

Map、flatMap区别

map:对流中每一个元素进行处理
flatMap:流扁平化,让你把一个流中的“每个值”都换成另一个流,然后把所有的流连接起来成为一个流
总结:map是对一级元素进行操作,flatmap是对二级元素操作。
本质区别:map返回一个值;flatmap返回一个流,多个值。

应用场景:map对集合中每个元素加工,返回加工后结果;flatmap对集合中每个元素加工后,做扁平化处理后(拆分层级,放到同一层)然后返回

/**
* 方法一
* 功能描述: 通过使用map、flatMap把字符串转换为字符输出对比区别
* @return : void
*/
@Test
public void flatMap2Map(){
List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
final Stream<Character> flatMap = strings.stream().flatMap(Java8StreamTest::getCharacterByString);
flatMap.forEach(System.out::println);
//----------------------------------------------
final Stream<Stream<Character>> mapStream = strings.stream().map(Java8StreamTest::getCharacterByString);
//mapStream.forEach(System.out::println);
System.out.println("------------------------------------------------");
mapStream.forEach(stream-> {stream.forEach(character->{System.out.println(character);});});

}

公共方法(字符串转换为字符流)

/**
* 功能描述:字符串转换为字符流
* @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();
}

 终止操作符:

1)anyMatch

/**
* 功能描述 : 判断集合中是否至少存在一个元素满足条件
* @return : void
*/
@Test
public void anyMatch(){
List<String> strings = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
boolean b = strings.stream().anyMatch(s -> s == "abc");
System.out.println(b);
}
2)allMatch

/**
* 功能描述 : 判断集合中是否所有元素都满足条件
* @return : void
*/
@Test
public void allMatch(){
List<String> strings = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
boolean b = strings.stream().allMatch(s -> s == "abc");
System.out.println(b);
}
3)noneMatch

/**
* 功能描述 : 判断集合中是否所有元素都不满足条件
* @return : void
*/
@Test
public void noneMatch(){
List<String> strings = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
boolean b = strings.stream().noneMatch(s -> s == "abc");
System.out.println(b);
}
4)findAny

/**
* 功能描述 : 返回当前流中任意元素
* @return : void
*/
@Test
public void findAny(){
List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
Optional<String> any = strings.stream().findAny();
if(any.isPresent()) out.println(any.get());
}
5)findFirst

/**
* 功能描述 : 返回当前流中第一个元素
* @return : void
*/
@Test
public void findFirst(){
List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
Optional<String> first = strings.stream().findFirst();
if(first.isPresent()) System.out.println(first.get());
}
6)forEach java

/**
* 功能描述 : 遍历流
* @return : void
*/
@Test
public void foreach(){
List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
strings.stream().forEach(s -> System.out.println(s));
}
7)collect

/**
* 功能描述 : 流转换为其他形式
* @return : void
*/
@Test
public void collect(){
List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
Set<String> set = strings.stream().collect(Collectors.toSet());
List<String> list = strings.stream().collect(Collectors.toList());
Map<String, String> map = strings.stream().collect(Collectors.toMap(v ->v.concat("_name"), v1 -> v1, (v1, v2) -> v1));
System.out.println(set);
System.out.println(list);
System.out.println(map);
}
8)reduce

/**
* 功能描述 : 将流中元素反复结合起来,得到一个值
* @return : void
*/
@Test
public void reduce(){
List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
//reduce方法一
Optional<String> reduce1 = strings.stream().reduce((acc,item) -> {return acc+item;});
//reduce方法二
String reduce2 = strings.stream().reduce("itcast", (acc, item) -> {
return acc + item;
});
//reduce方法三
ArrayList<String> reduce3 = strings.stream().reduce(
new ArrayList<String>(),
new BiFunction<ArrayList<String>, String, ArrayList<String>>() {
@Override
public ArrayList<String> apply(ArrayList<String> acc, String item) {
acc.add(item);
return acc;
}
},
new BinaryOperator<ArrayList<String>>() {
@Override
public ArrayList<String> apply(ArrayList<String> acc, ArrayList<String> item) {
return acc;
}
}
);
if(reduce1.isPresent())out.println(reduce1.get());
System.out.println(reduce2);
System.out.println(reduce3);
}

9)count

/**
* 功能描述 : 返回流中元素总数
* @return : void
*/
@Test
public void count(){
List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
long count = strings.stream().count();
System.out.println(count);
}

forEach

forEach 方法接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式。

// Java 8
roster.stream()
 .filter(p -> p.getGender() == Person.Sex.MALE)
 .forEach(p -> System.out.println(p.getName()));
// Pre-Java 8
for (Person p : roster) {
 if (p.getGender() == Person.Sex.MALE) {
 System.out.println(p.getName());
 }
}

map/flatMap

转换成大写字母:
List<String> output = wordList.stream().
map(String::toUpperCase).
collect(Collectors.toList());

输出平方数:
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
List<Integer> squareNums = nums.stream().
map(n -> n * n).
collect(Collectors.toList());

flatMap一对多:
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:

留下偶数:
Integer[] sixNums = {1, 2, 3, 4, 5, 6};
Integer[] evens =
Stream.of(sixNums).filter(n -> n%2 == 0).toArray(Integer[]::new);

把单词挑出来:
 List<String> output = reader.lines().
 flatMap(line -> Stream.of(line.split(REGEXP))).
 filter(word -> word.length() > 0).
 collect(Collectors.toList());
peek:不是一个最终操作,不会影响“哪些元素会流过”,所以十分适合在调试的时候,用来打印出流经管道的元素。forEach 不能修改自己包含的本地变量值,也不能用 break/return 之类的关键字提前结束循环。
Stream.of("one", "two", "three", "four")
 .filter(e -> e.length() > 3)
 .peek(e -> System.out.println("Filtered value: " + e))
 .map(String::toUpperCase)
 .peek(e -> System.out.println("Mapped value: " + e))
 .collect(Collectors.toList());

reduce:这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce

// 字符串连接,concat = "ABCD"
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat); 
// 求最小值,minValue = -3.0
double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min); 
// 求和,sumValue = 10, 有起始值
int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
// 求和,sumValue = 10, 无起始值
sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
// 过滤,字符串连接,concat = "ace"
concat = Stream.of("a", "B", "c", "D", "e", "F").
 filter(x -> x.compareTo("Z") > 0).
 reduce("", String::concat);

sorted:对 Stream 的排序通过 sorted 进行,它比数组的排序更强之处在于你可以首先对 Stream 进行各类 map、filter、limit、skip 甚至 distinct 来减少元素数量后,再排序,这能帮助程序明显缩短执行时间。

List<Person> persons = new ArrayList();
 for (int i = 1; i <= 5; i++) {
 Person person = new Person(i, "name" + i);
 persons.add(person);
 }
List<Person> personList2 = persons.stream().limit(2).sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).collect(Collectors.toList());
System.out.println(personList2);

 min/max/distinct

找出字符最长的一行:
BufferedReader br = new BufferedReader(new FileReader("c:\\SUService.log"));
int longest = br.lines().
 mapToInt(String::length).
 max().
 getAsInt();
br.close();
System.out.println(longest);


 用distinct找出全文的单词,转小写,并排序:
List<String> words = br.lines().
 flatMap(line -> Stream.of(line.split(" "))).
 filter(word -> word.length() > 0).
 map(String::toLowerCase).
 distinct().
 sorted().
 collect(Collectors.toList());
br.close();
System.out.println(words);

limit和skip

这是一个有 10,000 个元素的 Stream,但在 short-circuiting 操作 limit 和 skip 的作用下,管道中 map 操作指定的 getName() 方法的执行次数为 limit 所限定的 10 次,而最终返回结果在跳过前 3 个元素后只有后面 7 个返回。
public void testLimitAndSkip() {
 List<Person> persons = new ArrayList();
 for (int i = 1; i <= 10000; i++) {
 Person person = new Person(i, "name" + i);
 persons.add(person);
 }
List<String> personList2 = persons.stream().
map(Person::getName).limit(10).skip(3).collect(Collectors.toList());
 System.out.println(personList2);
}
private class Person {
 public int no;
 private String name;
 public Person (int no, String name) {
 this.no = no;
 this.name = name;
 }
 public String getName() {
 System.out.println(name);
 return name;
 }
}

Stream 有三个 match 方法,从语义上说:

  • allMatch:Stream 中全部元素符合传入的 predicate,返回 true
  • anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
  • noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true

它们都不是要遍历全部元素才能返回结果。例如 allMatch 只要一个元素不满足条件,就 skip 剩下的所有元素,返回 false。对清单 13 中的 Person 类稍做修改,加入一个 age 属性和 getAge 方法。

List<Person> persons = new ArrayList();
persons.add(new Person(1, "name" + 1, 10));
persons.add(new Person(2, "name" + 2, 21));
persons.add(new Person(3, "name" + 3, 34));
persons.add(new Person(4, "name" + 4, 6));
persons.add(new Person(5, "name" + 5, 55));
boolean isAllAdult = persons.stream().
 allMatch(p -> p.getAge() > 18);
System.out.println("All are adult? " + isAllAdult);
boolean isThereAnyChild = persons.stream().
 anyMatch(p -> p.getAge() < 12);
System.out.println("Any child? " + isThereAnyChild);

 

Stream.generate

  通过实现 Supplier 接口,你可以自己来控制流的生成。

Stream.generate(new PersonSupplier()).
limit(10).
forEach(p -> System.out.println(p.getName() + ", " + p.getAge()));
private class PersonSupplier implements Supplier<Person> {
 private int index = 0;
 private Random random = new Random();
 @Override
 public Person get() {
 return new Person(index++, "StormTestUser" + index, random.nextInt(100));
 }
}

 Collectors 来进行分组操作:

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());
}



按照未成年人和成年人归组:
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());

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值