JDK8 新特性总结
一、lambda表达式
1.语法
(parameter)->{表达式;} 或
(parameter)->{处理语句;}
2.含义
lambda表达式要看成是一个函数(方法),有方法的(入参 )和 {方法体}组成
3.lambda表达式会对应的一个函数接口的某个方法。
例如:
List.foreach(e->{e.getAge})
lambda表达式e->{e.getAge}对应的函数接口的方法是Consumer<E>接口的accept(E e)方法, 所谓:万变不离其宗,只要记住这个宗,任他怎么变,也不会难道自己
4.对类方法的引用的lambda表达式
语法:
类名::类的方法名
例如:
E::getAge 等同于 (e)->{e.getAge()}
第一种方法引用是构造方法引用,语法是:Class::new ,对于泛型来说语法是:Class<T >::new,请注意构造方法没有参数:
final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
第二种方法引用是静态方法引用,语法是:Class::static_method请注意这个静态方法只支持一个类型为Car的参数。
cars.forEach( Car::collide );
第三种方法引用是类实例的方法引用,语法是:Class::method请注意方法没有参数。
cars.forEach( Car::repair );
最后一种方法引用是引用特殊类的方法,语法是:instance::method,请注意只接受Car类型的一个参数。
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
二、函数接口
1.什么是函数接口
函数接口是一种只有一个方法的接口, 像这样的函数接口可以隐式的转换成lambda表达式
缺点:如果有人在此接口多添加任何一个接口,就会导致编译失败
补救:JDK8提供了一个@FunctionInterface的注解表明函数接口的目的, 记住:接口的默认方法和静态方法不违反函数接口的约定(或定义)
科普-> 匿名内部类:没有类名,且只使用一次,必须继承一个类或实现一个接口 。例如:new Runnable() { public void run(){}} 就是匿名内部类,没有类名实现了Runable接口中的方法。
Runnable r = new Runnable() {
public void run() {
System.out.print(i + " ");
}
};
2.如何定义函数接口
在接口名上加上注解@FunctionInterface, 且接口中只有一个方法(除了:默认方法 和 静态方法),如果有多个方法此类会有错误提示在注解@FunctionInterface上。
三、接口的默认方法和静态方法
1、默认方法
JDK8新概念之一:在接口中新增默认方法,新增的默认的方法必须要有实现,空实现也可以。此默认方法可以被实现类继承,实现类也可以重新默认方法。一个接口可以定义多个default 方法
2.静态方法
JDK8新概念之一:在接口中新增静态方法,新增的静态的方法必须要有实现,空实现也可以。此静态方法只能被此静态方法所在的接口调用,接口的子类都不可以调用此静态方法。一个接口可以定义多个static方法
四、注解
1.重复注解
jdk8之前同一个注解在同一个地方不能超过一次
现在jdk8允许重复注解,但是 定义这个注解的时候需要加@Repeatable (这个注解的数组注解定义类)注解
package com.javacodegeeks.java8.repeatable.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class RepeatingAnnotations { @Target( ElementType.TYPE ) @Retention( RetentionPolicy.RUNTIME ) public @interface Filters { Filter[] value(); } @Target( ElementType.TYPE ) @Retention( RetentionPolicy.RUNTIME ) @Repeatable( Filters.class ) public @interface Filter { String value(); }; @Filter( "filter1" ) @Filter( "filter2" ) public interface Filterable { } public static void main(String[] args) { for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) { System.out.println( filter.value() ); } } }
2.注解的扩展
JDK8新增了ElementType.TYPE_USE 和 ElementType.TYPE_PARAMETER
ElementType.TYPE_USE 针对类型(也叫类)和类型参数,可以限制哪个类型可以进行注解。能在局部变量、泛型类、父类和接口的实现处使用,甚至能在方法上声明异常的地方使用
ElementType.TYPE_PARAMETER 只针对类型参数TypeParameterClass<@TypeParameterAnnotation T>
ElementType.TYPE_PARAMETER
ElementType.TYPE_PARAMETER(Type parameter declaration) 用来标注类型参数。
@Target(ElementType.TYPE_PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface TypeParameterAnnotation { } // 如下是该注解的使用例子 public class TypeParameterClass<@TypeParameterAnnotation T> { public <@TypeParameterAnnotation U> T foo(T t) { return null; } }
ElementType.TYPE_USE
ElementType.TYPE_USE(Use of a type) 能标注任何类型名称,包括上面这个(ElementType.TYPE_PARAMETER的)例子。
public class TestTypeUse { @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) public @interface TypeUseAnnotation { } public static @TypeUseAnnotation class TypeUseClass<@TypeUseAnnotation T> extends @TypeUseAnnotation Object { public void foo(@TypeUseAnnotation T t) throws @TypeUseAnnotation Exception { } }
// 如下注解的使用都是合法的
@SuppressWarnings({ "rawtypes", "unused", "resource" }) public static void main(String[] args) throws Exception { TypeUseClass<@TypeUseAnnotation String> typeUseClass = new @TypeUseAnnotation TypeUseClass<>(); typeUseClass.foo(""); List<@TypeUseAnnotation Comparable> list1 = new ArrayList<>(); List<? extends Comparable> list2 = new ArrayList<@TypeUseAnnotation Comparable>(); @TypeUseAnnotation String text = (@TypeUseAnnotation String)new Object(); java.util. @TypeUseAnnotation Scanner console = new java.util.@TypeUseAnnotation Scanner(System.in); } }
注意:@TypeUseAnnotation 的位置应该在包名右边,类型左边,以下使用例子是错误的,除非给该注解的 @Target 参数里面加上 ElementType.LOCAL_VARIABLE。
@TypeUseAnnotation java.lang.String text;
3.更强的类型推断
Java 8的编译器能更加智能地推断出参数的类型。
public class Value<T> { public static<T> T defaultValue() { return null; } public T getOrDefault(T value, T defaultValue) { return (value != null) ? value : defaultValue; } } final Value<String> value = new Value<>(); value.getOrDefault( "22", Value.defaultValue());
Value.defaultValue()
的类型参数能推断出来,不需要写成 Value.<String>defaultValue()
。
五、参数名称
如何把参数迷名称保存在java字节码里,并让这些名字在运行时可用。Java 8 终于把这个需求加入到了Java语言(使用反射API和Parameter.getName() 方法)和字节码里(使用java编译命令javac的–parameters xx.java参数)
package com.javacodegeeks.java8.parameter.names; import java.lang.reflect.Method; import java.lang.reflect.Parameter; public class ParameterNames { public static void main(String[] args) throws Exception { Method method = ParameterNames.class.getMethod( "main", String[].class ); for( final Parameter parameter: method.getParameters() ) { System.out.println( "Parameter: " + parameter.getName() ); } } }
六、容器:Optional(可选的)
Optional<SomeType> getSomeValue() { // 返回一个空的Optional类型; return Optional.empty(); } Optional<SomeType> getSomeValue() { SomeType value = ...; // 使用这个方法,值不可以为空,否则抛exception return Optional.of(value); } Optional<SomeType> getSomeValue() { SomeType value = ...; // 使用这个方法,值可以为空,如果为空返回Optional.empty return Optional.ofNullable(value);
public static void optional(){ Optional<String> ot = Optional.ofNullable(null); System.out.println(ot.isPresent()); System.out.println(ot.orElse("ss")); System.out.println(ot.orElseGet(()->"ww")); System.out.println(ot.isPresent()?ot.get():null); }
输出
false ss ww null Process finished with exit code 0
具体Optional用法参考:点这里链接Optional的详情
七、日期
参考点击这里
/** * Date 和 LocalDateTime 转换介质为Instant(某一是时刻/瞬间) */ public static void DateToLocalDateTime(){ Date date = new Date(); // 入 Instant instant = date.toInstant();// 将Date对象转换成Instant对象 // 出 Date from = Date.from(instant);// 将Instant对象转换成Date对象 Clock clock = Clock.systemDefaultZone(); Instant instant1 = clock.instant(); Instant now = Instant.now(); //获取当前的时间戳 Instant now1 = Instant.now(clock); LocalDateTime localDateTime = LocalDateTime.ofInstant(instant1, ZoneId.systemDefault());//将Instant对象转换成LocalDateTime对象 Instant instant2 = localDateTime.toInstant(ZoneOffset.UTC); // 最常用(入、出) ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault()); Instant instant3 = zonedDateTime.toInstant(); Date from1 = Date.from(instant3); } /** * 时差信息的日期和时间 * ZoneOffset类用来表示时区,举例来说印度与GMT或UTC标准时区相差+05:30,可以通过ZoneOffset.of()静态方法来 获取对应的时区。 * 一旦得到了时差就可以通过传入LocalDateTime和ZoneOffset来创建一个OffSetDateTime对象 */ public static void zoneOffset() { LocalDateTime now = LocalDateTime.now(); System.out.println(now); ZoneOffset of = ZoneOffset.of("+05:30"); OffsetDateTime of1 = OffsetDateTime.of(now, of); System.out.println(of1); } /** * 相差期间 */ public static void duration(){ LocalDateTime from = LocalDateTime.of(2017, Month.DECEMBER, 20, 0, 0, 0); LocalDateTime to = LocalDateTime.of(2018, Month.DECEMBER, 20, 0, 0, 0); Duration between = Duration.between(from, to); //期间 System.out.println(between.toDays()); //相差期间为:365 天 System.out.println(between.toHours());//相差期间为:8760 小时 } /** * 区域日期时间 --- 最完整的日期时间,包含时区和相对UTC或格林威治的时差 */ public static void zonedDateTime() { ZonedDateTime now = ZonedDateTime.now(); ZonedDateTime now1 = ZonedDateTime.now(Clock.systemUTC()); ZonedDateTime now2 = ZonedDateTime.now(Clock.systemDefaultZone()); ZonedDateTime now3 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")); System.out.println(now); //2017-09-20T09:27:31.203+08:00[Asia/Shanghai] System.out.println(now1);// 2017-09-20T01:27:31.204Z System.out.println(now2);//2017-09-20T09:27:31.204+08:00[Asia/Shanghai] System.out.println(now3);//2017-09-20T09:27:31.204+08:00[Asia/Shanghai] } /** * 日期时间 --- 组合了日期和时间,但不包含时差和时区信息 */ public static void LocalDateTime() { LocalDateTime now = LocalDateTime.now();// 获取本土日期时间 LocalDateTime now1 = LocalDateTime.now(Clock.systemUTC());// 世界标准日期时间(美国日期时间)和本土日期时间有时差 LocalDateTime now2 = LocalDateTime.now(Clock.systemDefaultZone());// 获取本土日期时间 System.out.println(now); System.out.println(now1); System.out.println(now2); // 本土日期时间格式化 System.out.println(now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL))); //2017年9月19日 星期二 System.out.println(now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG))); //2017年9月19日 System.out.println(now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM))); //2017-9-19 System.out.println(now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT))); //17-9-19 //System.out.println(now.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL))); //Time无FULL System.out.println(now.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.LONG))); //下午06时18分55秒 System.out.println(now.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT))); //下午6:19 System.out.println(now.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM))); //18:18:35 System.out.println(now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG))); //2017年9月19日 下午06时18分55秒 System.out.println(now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM))); //2017-9-19 18:18:35 System.out.println(now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT))); //17-9-19 下午6:19 System.out.println(now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL,FormatStyle.SHORT))); //日期长,时间短:2017年9月19日 星期二 下午6:24 // 自定义 System.out.println(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"))); //日期长,时间短:2017年9月19日 星期二 下午6:24 System.out.println(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss", Locale.getDefault()))); //日期长,时间短:2017年9月19日 星期二 下午6:24 System.out.println(now.format(DateTimeFormatter.BASIC_ISO_DATE)); //20170919 System.out.println(now.format(DateTimeFormatter.ISO_TIME)); //18:58:36.494 System.out.println(now.format(DateTimeFormatter.ISO_DATE)); //2017-09-19 System.out.println(now.format(DateTimeFormatter.ISO_DATE_TIME)); //2017-09-19T18:54:05.264 System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE)); //2017-09-19 System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_TIME)); //18:57:07.175 System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); //2017-09-19T18:57:24.485 LocalDateTime parse = LocalDateTime.parse("2012-10-11", DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")); System.out.println(parse); System.out.println(now); //2017-09-19T18:57:24.485 } /** * 本地时间 */ public static void localTime(){ // 获取本地时间实例 LocalTime now = LocalTime.now(); // 也是本土时间 LocalTime now1 = LocalTime.now(Clock.systemUTC()); // 世界标准时间(美国时间)和本土时间有时差 LocalTime now2 = LocalTime.now(Clock.systemDefaultZone());// 获取本土时间 System.out.println(now); System.out.println(now1); System.out.println(now2); // 时间格式化 System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_TIME)); // 格式化时间 // 时间的加减 System.out.println(now.plusHours(1)); // 小时加1 System.out.println(now.plusHours(-1)); // 小时减1 // 时分秒的获取 System.out.println(now.getHour()); // 获取小时 System.out.println(now.getMinute()); // 获取分钟 // 处理指定时间 LocalTime from = LocalTime.of(12, 0, 0); LocalTime to = LocalTime.of(14, 0, 0); System.out.println(from.withHour(11));//11:00 System.out.println(from);//12:00 System.out.println(to);//14:00 // 时间的判断 System.out.println(from.equals(to));//false System.out.println(from.isBefore(to));//true System.out.println(to.isAfter(from));// true } /** * 本地日期 */ public static void localDate(){ //日期对像的获取 LocalDate now = LocalDate.now();// 也是本土日期 LocalDate now1 = LocalDate.now(Clock.systemUTC());// 世界标准日期(美国日期) LocalDate now2 = LocalDate.now(Clock.systemDefaultZone());// 获取本土日期 System.out.println(now); System.out.println(now1); System.out.println(now2); // 日期的格式化 System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE)); // 日期的加减(年月日) System.out.println(now.plusMonths(1));//月加1 System.out.println(now.plusMonths(-1));//月减1 System.out.println(now.plus(1, ChronoUnit.WEEKS));//now上添加一个星期 // 获取年月日 System.out.println(now.getYear());//年 System.out.println(now.getMonthValue());//月 System.out.println(now.getDayOfMonth());//日 System.out.println(now.getDayOfWeek());//星期几 WEDNESDAY System.out.println(now.getDayOfYear());//一年中的第几天 263 // 处理指定日期 LocalDate from = LocalDate.of(2017, Month.APRIL, 2);//指定2017-04-02 LocalDate to = LocalDate.of(2017, 8, 2);//2017-08-02 System.out.println(to.withDayOfMonth(9));//2017-08-09 System.out.println(to.withMonth(6));//2017-06-02 System.out.println(from);//2017-04-02 System.out.println(to);//2017-08-02 // 日期的判断 --- 如果比较的日期是字符型的,需要先解析成日期对象再作判断 System.out.println(from.equals(to)); // 输出false System.out.println(from.isBefore(to)); // true System.out.println(to.isAfter(from)); // true System.out.println(to.isEqual(from)); // false System.out.println(to.isLeapYear()); // 判断LocalDate对象to是否是闰年 false Period between = Period.between(from, to);//和 duration 进行对比下 System.out.println(between.getMonths());// 计算两个日期之间的天数、周数或月数 计算from和to相差的月数 返回4 System.out.println(between.getDays());// 计算两个日期之间的天数、周数或月数 计算from和to相差的日数 返回0 System.out.println(between.getYears());// 计算两个日期之间的天数、周数或月数 计算from和to相差的年数 返回0 // 日期的月日(MonthDay), 没有年(比如:每年你的生日,圣诞节),每年都重复的日子.还说有年月(YearMonth) MonthDay nowMothDay = MonthDay.now(); MonthDay nowFrom = MonthDay.from(LocalDate.now()); MonthDay nowTo = MonthDay.of(from.getMonthValue(), from.getDayOfMonth()); if (nowFrom.equals(nowTo)) {// 判断当前月日是否是指定的月日 System.out.println("Today is your birthday"); } //年月(YearMonth) YearMonth now3 = YearMonth.now(); System.out.println(now3.lengthOfMonth());// 返回当月的天数 30天 System.out.println(now3.lengthOfYear());// 返回当月的天数 365天 } /** * 时钟 和 瞬时实例 */ public static void clock(){ Clock clock = Clock.systemUTC();// 世界标准时钟 Clock clock2 = Clock.systemDefaultZone();// 获取本土时钟 System.out.println(clock.getZone());//Z System.out.println(clock.instant());//2017-09-20T01:43:40.557Z System.out.println(clock.millis());//1505871820578 System.out.println(clock2.getZone());//Asia/Shanghai System.out.println(clock2.instant());//2017-09-20T01:44:57.503Z System.out.println(clock2.millis());//1505871897503 Instant instant = clock.instant(); // 获取瞬时 实例 }
八、Stream
点击这里讲解Stream单独篇 这是部分案例 这个例子也不错 groupBy
/** * Stream 不是集合,不是数据结构不保存数据,它是有关算法和计算的,更新一个高级的iterator */ public static void streams() { /** * 1.其它数据结构转换为Stream(流生成Stream对象) */ List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); Stream<String> stream1 = Arrays.stream(new String[]{"1", "2"}); Stream<Integer> integerStream = Stream.of(1, 2, 3); // boxing 和 unboxing 会很耗时 使用IntStream更合理 // 数值流的构造 IntStream intStream = IntStream.of(1, 2, 3); LongStream longStream = LongStream.of(1L, 2L, 3L); DoubleStream doubleStream = DoubleStream.of(1d, 2d, 3d); IntStream range = IntStream.range(1, 10); // 输出1-9,不包括10 IntStream range2 = IntStream.rangeClosed(1, 10); // 输出1-10,包括10 range.forEach((System.out::println));// 1-9 range2.forEach((System.out::println));// 1-10 /** * 2.流转换为其它数据结构(一个 Stream 只可以使用一次) */ // Array String[] strArray1 = stream.toArray(String[]::new); int[] ints = intStream.toArray(); System.out.println(strArray1.length);//3 System.out.println(ints.length);//3 // Collection List<String> list1 = stream1.collect(Collectors.toList()); List<Integer> list2 = integerStream.collect(Collectors.toCollection(ArrayList::new)); Set set1 = longStream.boxed().collect(Collectors.toSet()); Stack stack1 = doubleStream.boxed().collect(Collectors.toCollection(Stack::new)); System.out.println(list1);//[1, 2] System.out.println(list2);//[1, 2, 3] System.out.println(set1);//[1, 2, 3] System.out.println(stack1);//[1.0, 2.0, 3.0] // String String str = strings.stream().collect(Collectors.joining()); System.out.println(str);// abc /** * 3.流中元素的操作 (集合的聚合操作【对Stream的使用就是实现一个 filter-map-reduce 过程,产生一个最终结果】) */ /** * Intermediate (流的中间操作是lazy的,并没有正在开始流的遍历【将转换函数输入集合中】) * * 包括的操作:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered */ /** * map,mapToInt, flatMap */ Stream.of("a", "b", "c").map(String::toUpperCase).collect(Collectors.toList());//map(1:1映射)作用就是把 input Stream 的每一个元素(这里是string集合的一个元素,或是对象集合的一个对象),映射成 output Stream 的另外一个元素(转换成一个大写的一个对象等) Stream.of("1", "2", "3").mapToInt(value -> Integer.parseInt(value)*Integer.parseInt(value));// 将输入的对象转换成输出的Int对象 //flatMap将List<List<String>>结合转换成List<String> 将一个上层的List<List<String>>转成底层的List<String> Stream<Integer> flatMap = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6)).flatMap(integers -> integers.stream());//flatMap(1:N 映射)层级结构扁平化 输入为一个List,输出为Integer集合,一个list元素转换成了多个Integer元素。flatMap 把 input Stream 中的层级结构扁平化,就是将最底层元素抽出来放到一起,最终 output 的新 Stream 里面已经没有 List 了,都是直接的数字。 System.out.println(flatMap.collect(Collectors.toList())); System.out.println(Stream.of("a", "b", "c").filter(s -> {return s.equals("a");}).findAny());// filter(你想要的数据的条件) 对原始 Stream 进行某项测试,通过测试的元素被留下来生成一个新 Stream System.out.println(Stream.of("a", "b", "a").distinct().collect(Collectors.toList()));//distinct()去重复 [a, b] System.out.println(Stream.of("a", "b", "c").sorted(Comparator.reverseOrder()).collect(Collectors.toList()));//sorted()顺序排列 Comparator.reverseOrder()反转顺序 System.out.println(Stream.of("a", "b", "c").sorted(Comparator.comparing(String::toString).reversed()).collect(Collectors.toList()));//sorted()顺序排列 comparatorObj.reversed()反转顺序 System.out.println(Stream.of("a", "b", "c").peek(s -> {s.length();s.toUpperCase();}).collect(Collectors.toList()));//peek()类似foreach()但是他不会消费Stream流foreach会 System.out.println(Stream.of("a", "b", "c").limit(2).collect(Collectors.toList()));//[a, b] 从第一个开始到最多size这里是2的集合 System.out.println(Stream.of("a", "b", "c").skip(1).collect(Collectors.toList()));//skip(开始的索引)包含索引上的值 [b, c] System.out.println(Stream.of("a", "b", "c").parallel().collect(Collectors.toList()));//parallel()并发stream适合在多线程中使用 , 管道来说,如果其元素是有序的,那么 limit 操作的成本会比较大,因为它的返回对象必须是前 n 个也有一样次序的元素。取而代之的策略是取消元素间的次序,或者不要用 parallel Stream System.out.println(Stream.of("a", "b", "c").sequential().collect(Collectors.toList()));//sequential()有序 System.out.println(Stream.of("a", "b", "c").unordered().collect(Collectors.toList()));//unordered()无序序 /** * Terminal (流的最终操作才会真正开始流的遍历,并且会生成一个结果,流被用光,无法再被操作【执行转换函数集合】) * * 包括的操作:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator * */ Stream.of("a", "b", "c").parallel().forEach(s -> System.out.println(s));// 并发处理的时候,forEach是无序的[b,c,a] ,非并发是有序的 Stream.of("a", "b", "c").parallel().forEachOrdered(s -> System.out.println(s));// 并发处理的时候,forEachOrdered是有序的[a,b,c] (Collectors.toList()也可以保证顺序,都是通过ForEachOrderedTask实现的) ,非并发是有序的 System.out.println(Stream.of("a", "b", "c").parallel().collect(Collectors.toList()));// [a, b, c] String[] toArray = Stream.of("a", "b", "c").toArray(String[]::new); // 集合转数组 System.out.println(toArray); /** * reduce和reducing(聚合操作)方法 * reduce() 和 collect() 的区别是: * reduce() 的结果是一个值;例如:String reduce = Stream.of("a", "bb", "c").map(String::toUpperCase).reduce("w", (s, s2) -> s.concat(s2)); * collect() 可以对stream中的元素进行各种处理后,得到stream中元素的值; */ System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min));// 求最小值,minValue = -3.0 System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, (aDouble, aDouble2) -> {return Double.min(aDouble,aDouble2);}));// 求最小值,minValue = -3.0 System.out.println(Stream.of("a", "b", "c").reduce("-a", (s,s2)->{ System.out.println(s+"-"+s2); return s.concat(s2);}));// s2集合中的元素, 第一次为s2=a ,s=-a,第二次:s2=b ,s=为上次参数而返回的结果(s+s2)=-aa 返回结果:-a-a|-aa-b|-aab-c System.out.println(Stream.of("a", "b", "c").reduce("-a",(a,b)->{return a.concat(b);}));//-aabc; a为上次方法体运算后(a.concat(b))返回的结果(初始化为-a),b为集合中遍历的每个元素,不停的遍历计算 System.out.println(Stream.of("a", "bb", "c").collect(Collectors.reducing("w", String::toUpperCase, (s, s2) -> s.concat(s2)))); //和下面一行一样的意思 wABBC String reduce = Stream.of("a", "bb", "c").map(String::toUpperCase).reduce("w", (s, s2) -> s.concat(s2)); System.out.println(reduce);//wABBC /** * 数字Stream(IntStream,LongStream,DoubleStream) */ System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).mapToDouble(d->d).min().getAsDouble());// 求最小值,minValue = -3.0 min 和 max 的功能也可以通过对 Stream 元素先排序,再 findFirst 来实现 System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).mapToDouble(d->d).max().getAsDouble());// 求最最大值 System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).mapToDouble(d->d).sum());// 求最和 (数字Stream才有此方法) System.out.println(Stream.of("a", "bb", "ccc").collect(Collectors.summingInt(s->{return s.length();}))); // 求总和(元素中的某个属性返回Int)输出:6 System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).mapToDouble(d->d).average().getAsDouble());// 求平均数 -1.375 (数字Stream才有此方法) System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).collect(Collectors.averagingDouble((d) -> { return d; })));// 计算平均值,返回Double类型 System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).mapToDouble(d->d).distinct().max().getAsDouble());// 数字去重 1.0 System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).min(Comparator.naturalOrder()));// 求最小值,minValue = -3.0 通过对 Stream 元素先排序,再 findFirst 来实现 System.out.println(Stream.of(-1.5, 1.0, -3.0, -2.0).count());// 求集合的size /** * 4.Collectors的使用 */ // groupingBy() Map<Integer, List<String>> collect = Stream.of("a", "bb", "c").collect(Collectors.groupingBy((a) -> {return a.length();}));// 分组,默认是元素集合类型的 Map<Integer, Set<String>> collectSet = Stream.of("a", "bb", "c").collect(Collectors.groupingBy((a) -> {return a.length();},Collectors.toSet()));// 分组, ,Collectors.toSet()表示map的value是Set<T>集合,而不是List<t> Map<Integer, Long> collectCount = Stream.of("a", "bb", "c").collect(Collectors.groupingBy((a) -> {return a.length();},Collectors.counting()));// 分组, ,Collectors.counting()表示map的value是Long的数量 System.out.println(Stream.of("a", "bb", "c").collect(Collectors.groupingBy((a) -> {return a.length();})));// 分组 输出:{1=[a, c], 2=[bb]} System.out.println(Stream.of("a", "bb", "c").collect(Collectors.groupingByConcurrent(String::length))); // 分组groupingBy的并发版本 输出:{1=[a, c], 2=[bb]} // partitioningBy() Map<Boolean, List<String>> collect1 = Stream.of("a", "bb", "c").collect(Collectors.partitioningBy((a) -> { return a.length() > 1; }));// 分成2部分 true是返回符合条件的,false是其余部分 System.out.println(collect1); // {false=[a, c], true=[bb]} Map<String, String> collect2 = Stream.of("a", "bb", "ccc").collect(Collectors.toMap(key -> { return key; }, Function.identity()));// 返回的Map的key不能有重复,也就是toMap()的keyMapper不能重复,有重复会抛出异常 System.out.println(collect2); // {bb=bb, a=a, ccc=ccc} ArrayList<String> collect3 = Stream.of("a", "b", "c").collect(Collectors.toCollection(() -> { return new ArrayList<>(); }));// 返回 new的对象的集合 Stream.of("a", "b", "c").collect(Collectors.toCollection(HashSet::new)); System.out.println(collect3); // [a, b, c] String collect4 = Stream.of("a", "b", "c").collect(Collectors.joining());// 字符串集合组合成一个字符串,只适合字符串集合的 System.out.println(collect4); // abc String collect5 = Stream.of("a", "b", "c").collect(Collectors.joining("|"));// 字符串集合组合成一个字符串,且用界定符或连接符进行连接 System.out.println(collect5); // a|b|c String collect6 = Stream.of("a", "b", "c").collect(Collectors.joining("连接符", "前缀", "后缀")); System.out.println(collect6); // 前缀a连接符b连接符c后缀 Optional<String> collect7 = Stream.of("a", "bb", "ccc").max(Comparator.comparingInt(String::length)); // 获取最多哪个元素对象 System.out.println(collect7.get()); // .get()返回集合元素中的一个对象 String collect8 = Stream.of("a", "bb", "ccc").collect(Collectors.collectingAndThen(Collectors.maxBy((a, b) -> { return a.length() - b.length(); }), Optional::get)); System.out.println(collect8);//ccc String collect9 = Stream.of("a", "bb", "ccc").collect(Collectors.collectingAndThen(Collectors.minBy((a, b) -> { return a.length() - b.length(); }), Optional::get)); System.out.println(collect9);//a System.out.println(Stream.of("a", "bb", "c").collect(Collectors.counting())); // 计算数量 输出:3 Stream.of("a", "bb", "c").collect(Collectors.mapping(o -> o, Collectors.joining("||")));// 和下面一行一样的意思 a||bb||c Stream.of("a", "bb", "c").map(o -> o).collect(Collectors.joining("||")); /** * 概要统计(Int,Double,Long) */ IntSummaryStatistics collect10 = Stream.of("a", "bb", "c").collect(Collectors.summarizingInt(String::length));//Int概要统计对象 System.out.println(collect10.getAverage());//1.3333333333333333 System.out.println(collect10.getCount());//3 System.out.println(collect10.getSum());//4 System.out.println(collect10.getMax());//2 System.out.println(collect10.getMin());//1 /** * 流的短路 * * 包括的操作:anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit * * Stream 有三个 match 方法,从语义上说: * allMatch:Stream 中全部元素符合传入的 predicate,返回 true * anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true * noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true */ System.out.println(Stream.of("a", "bb", "c").allMatch(s -> {return s.length()>0;}));//true System.out.println(Stream.of("a", "bb", "c").anyMatch(s -> {return s.length()==2;}));//true System.out.println(Stream.of("a", "bb", "c").noneMatch(s -> {return s.length()>2;}));//true System.out.println(Stream.of("a", "bb", "c").findAny().get());//找到任何一个,一般是第一个 a System.out.println(Stream.of("a", "bb", "c").findFirst().get());//找到第一个 a System.out.println(Stream.of("a", "bb", "c").limit(3).collect(Collectors.toList()));//第一个到第3个元素获取 }
Java 8 Stream Distinct Examples
//非对象去重 Collection<String> list = Arrays.asList("A", "B", "C", "D", "A", "B", "C"); // Get collection without duplicate i.e. distinct only List<String> distinctElements = list.stream().distinct().collect(Collectors.toList()); //Let's verify distinct elements System.out.println(distinctElements); //对象去重 import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; public class JavaStreamDistinctExamples { public static void main(String[] args) { Person lokesh = new Person(1, "Lokesh", "Gupta"); Person brian = new Person(2, "Brian", "Clooney"); Person alex = new Person(3, "Alex", "Kolen"); //Add some random persons Collection<Person> list = Arrays.asList(lokesh,brian,alex,lokesh,brian,lokesh); // Get distinct only List<Person> distinctElements = list.stream().filter(distinctByKey(p -> p.getId())).collect(Collectors.toList()); // Let's verify distinct elements System.out.println(distinctElements); } public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) { Map<Object, Boolean> map = new ConcurrentHashMap<>(); return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; } } class Person { public Person(Integer id, String fname, String lname) { super(); this.id = id; this.fname = fname; this.lname = lname; } private Integer id; private String fname; private String lname; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getFname() { return fname; } public void setFname(String fname) { this.fname = fname; } public String getLname() { return lname; } public void setLname(String lname) { this.lname = lname; } @Override public String toString() { return "Person [id=" + id + ", fname=" + fname + ", lname=" + lname + "]"; } } Program Output: [ Person [id=1, fname=Lokesh, lname=Gupta], Person [id=2, fname=Brian, lname=Clooney], Person [id=3, fname=Alex, lname=Kolen] ]
public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) { Map<Object, Boolean> map = new ConcurrentHashMap<>(); System.out.println("我输出了一次,我是在循环之外的"); // 说明 // t就是Stream流的对象,t->{return true/false}是对Predicate的test(t)的实现,t是test(T)方法的入参,{return true/false}是test()的实现或说是方法体 // 而本方法的Function keyExtractor对象的实现(p -> p.getName()), // 其中p就是Stream流的对象和t是同一个概念,(p -> p.getName())是针对Function的app(T)的实现,p是app(T)方法的入参是个对象, p.getName()是对app()的实现 return t ->{ System.out.println("我输出了W次"+t); System.out.println("我输出了N次"+keyExtractor.apply(t)); return map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; }; //结果 //我输出了一次 //我输出了W次com.bean.Student@181eb93 //我输出了N次1 //我输出了W次com.bean.Student@91c18f //我输出了N次1 //我输出了W次com.bean.Student@a245ab //我输出了N次1 }