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
    }

  

posted @ 2017-09-14 15:47  不缺重头再来的勇气  阅读(1126)  评论(0编辑  收藏  举报