stream创建
String[] weeks = new String[]{"周一","周二","周三"};
Stream s1 = Arrays.stream(weeks);
Stream s2 = Stream.of(weeks);
Stream s3 = Stream.of("123");
Stream s4 = Arrays.asList(weeks).stream();
Stream s5 = Stream.iterate(0,x->x+1);
Stream<Integer> s6 = Stream.generate(() -> {
LocalTime time = LocalTime.now();
return time.getSecond();
});
其中s2,s3的创建方法的源码其实也用了s1的方法来实现的,s5,s6都是无线流,就是一直生成元素,s4就是直接通过集合获取流。
中间操作
filter
List<String> weeks = new ArrayList<>();
weeks.add("周一");
weeks.add("周二");
weeks.add("周三");
weeks.add("周四");
weeks.add("周五");
weeks.add("周六");
weeks.add("周七");
weeks.add("下周一");
weeks.add("下周二");
Stream<String> s1 = weeks.stream();
s1.filter((x) -> { return x.length() < 3;}).forEach(System.out::print);//周一周二周三周四周五周六周七
distinct
hashCode方法保证一样
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Test1112 test1112 = (Test1112) o;
return Objects.equals(name, test1112.name);
}
@Override
public int hashCode() {
return 5*age+name.hashCode();
}
}
public void test2(){
List<Test1112> testList = new ArrayList<>();
Test1112 day1 = new Test1112("f",1);
Test1112 day2 = new Test1112("a",2);
testList.add(day1);
testList.add(day2);
System.out.println("day1.hashCode == day2.hashCode :"+(day1.hashCode() == day2.hashCode()));//true
System.out.println("day1.equals(day2) :"+(day1.equals(day2)));//false
testList.stream().distinct().forEach(x -> {
System.out.println(x.toString());
});//打印出 两个
}
将两个对象的name属性改成一样的
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Test1112 test1112 = (Test1112) o;
return Objects.equals(name, test1112.name);
}
@Override
public int hashCode() {
return 5*age+name.hashCode();
}
}
public void test2(){
List<Test1112> testList = new ArrayList<>();
Test1112 day1 = new Test1112("a",1);
Test1112 day2 = new Test1112("a",2);
testList.add(day1);
testList.add(day2);
System.out.println("day1.hashCode == day2.hashCode :"+(day1.hashCode() == day2.hashCode()));//false
System.out.println("day1.equals(day2) :"+(day1.equals(day2)));//true
testList.stream().distinct().forEach(x -> {
System.out.println(x.toString());
});//打印出 两个
}
将名称和age属性都改成一样的
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Test1112 test1112 = (Test1112) o;
return Objects.equals(name, test1112.name);
}
@Override
public int hashCode() {
return 5*age+name.hashCode();
}
}
public void test2(){
List<Test1112> testList = new ArrayList<>();
Test1112 day1 = new Test1112("a",2);
Test1112 day2 = new Test1112("a",2);
testList.add(day1);
testList.add(day2);
System.out.println("day1.hashCode == day2.hashCode :"+(day1.hashCode() == day2.hashCode()));//true
System.out.println("day1.equals(day2) :"+(day1.equals(day2)));//true
testList.stream().distinct().forEach(x -> {
System.out.println(x.toString());
});//打印出 1
最终发现:distinct去重的依据是hashCode和equal方法都返回true才算是同一个。
sorted
List<Test1112> testList = new ArrayList<>();
Test1112 day2 = new Test1112("周二",5);
Test1112 day1 = new Test1112("周一",10);
Test1112 day3 = new Test1112("周三",6);
testList.add(day1);
testList.add(day2);
testList.add(day3);
testList.stream().sorted(Comparator.comparing(((x)->{return x.getAge();}),(age1,age2)->{return age1 - age2 ;})).forEach(System.out::print);
sorted方法可以放入自定义比较器,我这里选择的是放入两个参数的比较器,第一个参数我是用来确定两者比较的字段,我选用age字段的值进行比较,然后第二个参数就是比较的逻辑,age大的就是排在后面
map操作
map有几个方法名类似的
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
testList.stream().map(x -> {return x.getAge();}).forEach(x -> System.out.println(x));
我看效果就是把之前的元素进行一定的处理,改变了之前stream的泛型对象,然后再返回,当然也可以不改变泛型,我这边是改变了之前的stream泛型,之前是 泛型是Test1112对象,后来变成了Intger。
flatMap
flatMap也同样有几个类似名称的方法,
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
这边参数是一个Function 函数式接口,并且这个函数式接口的返回对象还是一个stream流,这个和之前的都不一样
List<Test1112> testList = new ArrayList<>();
Test1112 day2 = new Test1112("周二,下周二",33);
Test1112 day1 = new Test1112("周一,下周一",12);
Test1112 day3 = new Test1112("周三",31);
testList.add(day1);
testList.add(day2);
testList.add(day3);
testList.stream().flatMap(x -> {return Stream.of(x.getName().split(","));}).forEach(System.out::print);//周一下周一周二下周二周三
我想如果是组织树形式的数据集合用flatMap是不是就可以将这个组织树上的数据都给取下来,也就是扁平化成一个组织类型的集合。
anyMatch,noneMatch,allMatch
boolean anyMatch(Predicate<? super T> predicate);
boolean allMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);
可以看到返回结果是一个boolean值,是一个终止操作
findAny findFirst 也是一个终止操作,返回一个对象,其中findAny好像也一直返回第一个,但是我百度说是不一定的,也就没有深究。
reduce操作
reduce相关的有三个方法:
Optional<T> reduce(BinaryOperator<T> accumulator);
T reduce(T identity, BinaryOperator<T> accumulator);
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
看一下BinaryOperator源码可以发现继承了 BiFunction<T,T,T> 这个函数式接口
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
}
public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
}
}
再看一下BiFunction源码
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
里面的 R apply(T t, U u)方法,R参数式作为返回结果,所以reduce里的BinaryOperator accumulator函数式接口参数,就是两个形参,并且式有一个返回结果的方法,开始demo。
数据格式:
Test1112 day2 = new Test1112("周一",31);
Test1112 day1 = new Test1112("周二",32);
Test1112 day3 = new Test1112("周三",33);
一个参数的:
System.out.println(testList.stream().reduce((x,y) -> {returny.getAge()+x.getAge();}).get());
刚开始reduce里的函数式接口我是这么写的,但是报错,提示Bad return type in lambda expression: int cannot be converted to Test1112
说类型不匹配,我想testList.stream()里的泛型对象式Test1112,但是这里的返回结果是一个String,原来返回结果还要是一个Test1112对象才行,修改一下:
System.out.println(testList.stream().reduce((x,y) -> {return new Test1112(x.getName()+y.getName(),y.getAge()+x.getAge());}).get());
// Test1112{name='周一周二周三', age=96}
看结果就知道是先将周一 周二 的name 拼接,age相加之后,作为返回结果,再次与周三的做相同操作。
有两个参数方法:
T reduce(T identity, BinaryOperator accumulator);可以看到多出来的参数是一个对象,并且就是stream流泛型对象,我不清楚能干嘛,也是一样的我试了一下效果:
System.out.println(testList.stream().reduce(new Test1112("周四",4),(x,y)->{return new Test1112(x.getName()+y.getName(),x.getAge()+y.getAge());}));
// Test1112{name='周四周一周二周三', age=100}
也是一样的拼接,那直接把周四加到testList集合里也是可以一样的效果的,难道有顺序问题?后面的不想继续看了偷个懒。