java8以前HashMap存储结构以下图,将Map中的key进行哈希运算获得hashCode,当出现hashCode相同但equals不一样时称此现象为碰撞
,发生碰撞时会造成链表结构,取值时会遍历整个链表结构效率较低。java
java8采用的HashMap存储结构以下图,当发生碰撞造成的链表上元素个数大于8时,总容量大于64会将链表转换为红黑树。此种状况下除了添加元素慢一些,其他操做(查询,删除)均高于链表结构。算法
java8以前concurrentHashMap为HashTable的组合达到线程安全的效果,默认并发级别为16即concurrentHashMap由16个HashTable组成。java8采用CAS算法到达线程安全的效果,数据结构为java8的HashMap结构。数据库
注:hashMap起始默认容器大小为16,当容器元素个数到达75%(扩容因子)开始扩容,扩容一倍大小从新计算位置。编程
历史:以前不少公司生产的JVM早已没有永久代,只是SUN的JVM尚未淘汰永久代数组
java8将永久代变为元空间(MetaSpace)。以前永久代在JVM中分配,永久代基本不回收占用JVM内存空间。java8废弃永久代改成元空间,元空间在操做系统的内存上进行分配。安全
在函数式语言中,咱们只须要给函数分配变量,并将这个函数做为参数传递给其它函数就可实现特定的功能。而java如前言中所述,不能直接将方法看成一个参数传递。同时匿名内部类又存在诸多不便:语法过于冗余,匿名类中的this和变量名容易令人产生误解,类型载入和实例建立语义不够灵活,没法捕获非final的局部变量等。 Lambda 表达式的出现为 Java 添加了缺失的函数式编程特色,使咱们能将函数当作一等公民看待。数据结构
Lambda 表达式在Java 语言中引入了一个新的语法元素和操做符。这个操做符为->
,该操做符被称为Lambda 操做符或箭头操做符。它将Lambda 分为两个部分: 左侧:指定了Lambda 表达式须要的全部参数 右侧:指定了Lambda 体,即Lambda 表达式要执行的功能并发
Lambda表达式实现的必须是函数式接口。app
只包含一个抽象方法的接口,称为函数式接口。能够经过Lambda 表达式来建立该接口的对象。(若Lambda 表达式抛出一个受检异常,那么该异常须要在目标接口的抽象方法上进行声明)。咱们能够在任意函数式接口上使用@FunctionalInterface
注解,这样作能够检查它是不是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。框架
/** * 情景一:无参数,无返回值,一条语句 */ @Test public void test() throws Exception { Runnable r = () -> System.out.println("Hello Lambda"); r.run(); }
/** * 情景二:有一个参数,而且无返回值,一条语句 */ @Test public void test() throws Exception { Consumer<String> consumer = (x) -> System.out.println("Hello " + x); consumer.accept("Lambda"); }
/** * 情景三:有两个以上参数,多条语句 */ @Test public void test() throws Exception { Comparator<Integer> comparator = (x, y) -> { System.out.println("多条语句"); return Integer.compare(x, y); }; }
注:
{}
和return
,通常状况下省略。类型推断
。若是要写须要所有写上类型。①消费型接口
@FunctionalInterface public interface Consumer<T> { void accept(T t); //链式调用,以后继续调用消费型接口 default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
测试实例--消费型接口
/** * 消费型接口Consumer<T> */ @Test public void test1 () { consumo(500, (x) -> System.out.println(x)); } public void consumo (double money, Consumer<Double> c) { c.accept(money); }
②供给型接口
@FunctionalInterface public interface Supplier<T> { T get(); }
测试实例-供给型接口
/** * 供给型接口,Supplier<T> */ @Test public void test2 () { Random ran = new Random(); List<Integer> list = supplier(10, () -> ran.nextInt(10)); for (Integer i : list) { System.out.println(i); } } /** * 随机产生sum个数量得集合 * @param sum 集合内元素个数 * @param sup * @return */ public List<Integer> supplier(int sum, Supplier<Integer> sup){ List<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < sum; i++) { list.add(sup.get()); } return list; }
③函数型接口
@FunctionalInterface public interface Function<T, R> { R apply(T t); //链式调用,在调用此方法以前调用传入的函数式接口 default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } //链式调用,在调用此方法以后调用传入的函数式接口 default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } //返回输入的参数,Function.identity().apply("AAA")返回AAA static <T> Function<T, T> identity() { return t -> t; } }
函数型接口测试实例
/** * 函数型接口:Function<R, T> */ @Test public void test3 () { String s = strOperar(" asdf ", x -> x.substring(0, 2)); System.out.println(s); String s1 = strOperar(" asdf ", x -> x.trim()); System.out.println(s1); } /** * 字符串操做 * @param str 须要处理得字符串 * @param fun Function接口 * @return 处理以后得字符传 */ public String strOperar(String str, Function<String, String> fun) { return fun.apply(str); }
④断言型接口
@FunctionalInterface public interface Predicate<T> { boolean test(T t); //链式调用,须要同时知足条件 default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } //取相反值 default Predicate<T> negate() { return (t) -> !test(t); } //链式调用,只须要知足一个条件便可 default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
断言型接口测试实例
/** * 断言型接口:Predicate<T> */ @Test public void test4 () { List<Integer> l = new ArrayList<>(); l.add(102); l.add(172); l.add(13); l.add(82); l.add(109); List<Integer> list = filterInt(l, x -> (x > 100)); for (Integer integer : list) { System.out.println(integer); } } /** * 过滤集合 * @param list * @param pre * @return */ public List<Integer> filterInt(List<Integer> list, Predicate<Integer> pre){ List<Integer> l = new ArrayList<>(); for (Integer integer : list) { if (pre.test(integer)) l.add(integer); } return l; }
除了上述得4种类型得接口外还有其余的一些接口供咱们使用:
参数类型有2个,为T,U,返回值为R,其中方法为R apply(T t, U u)
参数为T,对参数为T的对象进行一元操做,并返回T类型结果,其中方法为T apply(T t)
当要传递给Lambda体的操做,已经有实现的方法了,可使用方法引用(实现抽象方法的参数列表和返回类型,必须与方法引用方法的参数列表和返回类型保持一致)
方法引用:使用操做符::
将方法名和对象或类的名字分隔开来。以下三种主要使用状况:
对象::实例方法
@Test public void test() throws Exception { PrintStream ps = System.out; Consumer<String> consumer = ps::println; consumer.accept("Lambda"); }
类::静态方法
@Test public void test() throws Exception { Comparator<Integer> comparator = Integer::compare; }
类::实例方法,第一个参数是此方法的调用者,第二个参数是此方法的参数时可使用ClassName::MethodName
@Test public void test() throws Exception { BiPredicate<String, String> predicate = String::equals; }
public void test() throws Exception { Supplier<Employee> supplier = Employee::new;//与函数式接口参数列表匹配调用对应的构造方法 supplier.get(); }
@Test public void test() throws Exception { //传入的参数必须是Integer,返回是一个数组 Function<Integer, Employee[]> function = Employee[]::new;//new Employee[num] }
Stream 是Java8 中处理集合的关键抽象概念,它能够指定你但愿对集合进行的操做,能够执行很是复杂的查找、过滤和映射数据等操做。使用Stream API 对集合数据进行操做,就相似于使用SQL 执行的数据库查询。也可使用Stream API 来并行执行操做。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
流是数据渠道,用于操做数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算”
1、建立Stream
@Test public void test() throws Exception { //一、经过Collection系列集合提供的stream()或parallelStream()获取 List<String> list = new ArrayList<String>(); Stream<String> stream1 = list.stream(); //二、经过Arrays中的静态方法stream()获取数组流 Employee[] employees = new Employee[10]; Stream<Employee> stream2 = Arrays.stream(employees); //三、经过Stream类中的静态方法of() Stream<String> stream3 = Stream.of("AAA","BBB","CCC"); //四、迭代建立无限流 Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 1); //五、生成建立无限流 Stream<Double> stream5 = Stream.generate(Math::random); }
2、中间操做
筛选
/** * filter——接受Lambda,从流中排除某些元素 * limit——截断流,使其元素不超过给定数量 * skip(n)——跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit互补
*/ @Test public void test() throws Exception { emps.stream().filter((e) -> e.getSalary() > 5000); emps.stream().limit(5); emps.stream().skip(5); emps.stream().distinct(); //此操做会发生短路,取出工资大于5000的两个其他再也不遍历 emps.stream().filter((e) -> e.getSalary() > 5000).limit(2); } ```
映射
/** * map——接收Lambda,将元素转换为其余形式或提取信息。接收一个函数做为参数,该参数会被应用到每一个元素上,并将其映射成一个新元素
*/ @Test public void test() throws Exception { emps.stream().map(Employee::getName); //会将【【A】,【B】,【C】】转换为【A,B,C】 List<List<String>> lls = Arrays.asList(Arrays.asList("A"),Arrays.asList("B"),Arrays.asList("C")); lls.stream().flatMap((ls) -> ls.stream()); } ```
排序
/** * sorted():天然排序
*/ @Test public void test() throws Exception { List<String> arr = Arrays.asList("AAA","BBB","CCC"); arr.stream().sorted();//天然排序 emps.stream().sorted((x, y) -> x.getAge().compareTo(y.getAge()));//定制排序 } ```
3、终止操做(终端操做)
查找与匹配
/** * allMatch:检查是否匹配全部元素 * anyMatch:检查是否至少匹配一个元素 * noneMatch:检查是否没有匹配全部元素 * findFirst:返回第一个元素 * findAny:返回任意一个元素 * count:返回元素个数 * max:返回流中最大元素
*/ @Test public void test() throws Exception { boolean allMatch = emps.stream().allMatch((e) -> e.getAge() > 18); //employees是否年龄都大于18 boolean anyMatch = emps.stream().anyMatch((e) -> e.getSalary() > 6000); //employees是否存在工资大于6k boolean noneMatch = emps.stream().noneMatch((e) -> e.getName().equals("小明"));//employees是否没有人叫小明 Optional<Employee> findFirst = emps.stream().findFirst(); //返回第一个元素 Optional<Employee> findAny = emps.parallelStream().findAny(); //返回任意一个元素,stream()会一直返回第一个 long count = emps.stream().count(); //返回元素个数 Optional<Employee> max = emps.stream().max((x, y) -> Integer.compare(x.getAge(),y.getAge())); //返回年龄最大的 Optional<Employee> min = emps.stream().min((x, y) -> Integer.compare(x.getAge(),y.getAge())); //返回年龄最小的 } ```
归约与收集
/** * 归约:reduce(T indetity, BinaryOperator) / reduce(BinaryOperator):能够将流中的元素反复结合起来获得一个新值
*/ @Test public void testReduce() throws Exception { emps.stream().map(Employee::getSalary).reduce(0.0, Double::sum); //计算工资总和 } /** * 收集:collect - 将流转换为其余形式,接收一个Collector接口实现,用于数据汇总 Collectors:工具类用于产生Collector实例 */ @Test public void testCollect() throws Exception { List<String> names = emps.stream().map(Employee::getName).collect(Collectors.toList()); // 转换为自定义数据类型 HashSet<Double> salarys = emps.stream().map(Employee::getSalary).collect(Collectors.toCollection(HashSet::new)); // 用收集器获得总个数 long count = emps.stream().collect(Collectors.counting()); // 取平均值 Double avg = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary)); // 取总和 Double sum = emps.stream().collect(Collectors.summingDouble(Employee::getSalary)); // 取最大值 Optional<Employee> max = emps.stream().collect(Collectors.maxBy( (x, y) -> Double.compare(x.getSalary(), y.getSalary()))); //拼接字符串 String joinNames = emps.stream().map(Employee::getName).collect(Collectors.joining(",")); // 经过summaryStatistics得到值 DoubleSummaryStatistics summaryStatistics = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));// 取总和 summaryStatistics.getAverage(); summaryStatistics.getCount(); summaryStatistics.getMax(); summaryStatistics.getMin(); summaryStatistics.getSum(); //分组,也能够进行多级分组 Map<Double, List<Employee>> groupSalary = emps.stream().collect(Collectors.groupingBy(Employee::getSalary)); //以工资分组 Map<String, List<Employee>> groupAge = emps.stream().collect(Collectors.groupingBy( (e) -> e.getAge() > 35 ? "中年" : "青年")); //以年龄分组 //分区是一种特殊的分组,结果 map至少包含两个不一样的分组一个true,一个false Map<Boolean, List<Employee>> partitionSalary = emps.stream().collect(Collectors.partitioningBy((e) -> e.getSalary() > 5000)); } ```
遍历
@Test public void test() throws Exception { emps.stream().forEach(System.out::println); }
Fork/Join 框架:就是在必要的状况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join 汇总。
采用工做窃取
模式(work-stealing): 当执行新的任务时它能够将其拆分分红更小的任务执行,并将小任务加到线程队列中,而后再从一个随机线程的队列中偷一个并把它放在本身的队列中。相对于通常的线程池实现,fork/join框架的优点体如今对其中包含的任务的处理方式上。在通常的线程池中,若是一个线程正在执行的任务因为某些缘由没法继续运行,那么该线程会处于等待状态。而在fork/join框架实现中,若是某个子问题因为等待另一个子问题的完成而没法继续运行。那么处理该子问题的线程会主动寻找其余还没有运行的子问题来执行。这种方式减小了线程的等待时间,提升了性能。
Fork/Join的好处
Fork/Join示例
public class ForkJoinCalculate extends RecursiveTask<Long> { private static final long serialVersionUID = 1L; private long start; private long end; private static final long THRESHOLD = 10000; public ForkJoinCalculate(long start, long end) { this.start = start; this.end = end; } @Override protected Long compute() { long length = end - start; if(length <= THRESHOLD) { long sum = 0; for (long i = start; i <= end; i++) { sum += i; } return sum; }else { long middle = (start + end) / 2; ForkJoinCalculate left = new ForkJoinCalculate(start,middle); left.fork(); ForkJoinCalculate right = new ForkJoinCalculate(middle + 1,end); right.fork(); return left.join() + right.join(); } } public static void main(String[] args) { ForkJoinPool pool = new ForkJoinPool(); ForkJoinCalculate calculate = new ForkJoinCalculate(1, 1000000000L); Long result = pool.invoke(calculate); System.out.println(result); } }
底层依旧使用的Fork/Join框架,使用的公共的ForkJoinPool,大大简化了Fork/Join框架的使用难度
@Test public void test() throws Exception { OptionalLong result = LongStream.rangeClosed(1, 10000000L).parallel().reduce(Long::sum); System.out.println(result.getAsLong()); }
Optional 类(java.util.Optional) 是一个容器类,表明一个值存在或不存在,原来用null 表示一个值不存在,如今Optional 能够更好的表达这个概念。而且能够避免空指针异常。
经常使用方法:
Java 8中容许接口中包含具备具体实现的方法,该方法称为默认方法
,使用 ==default==关键字修饰。Java 8中容许接口中定义和实现静态方法。
接口默认方法的”类优先”原则
若一个接口中定义了一个默认方法,而另一个父类或接口中又定义了一个同名的方法时选择父类中的方法。若是一个父类提供了具体的实现,那么接口中具备相同名称和参数的默认方法会被忽略。
接口冲突
若是一个父接口提供一个默认方法,而另外一个接口也提供了一个具备相同名称和参数列表的方法(无论方法是不是默认方法),那么必须覆盖该方法来解决冲突。
interface Foo { default String getFoo() { // 默认方法 return "foo"; } static String showFoo() { // 静态方法 System.out.println("foo"); } }
在可重复注解上使用@Repeatable
标注且提供容器类
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Repeatable(MyAnnotations.class) public @interface MyAnnotation { String value(); }
容器类必须提供可重复注解[] value()
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyAnnotations { MyAnnotation[] value(); }
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(Use of a type) 能标注任何类型名称
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); } }
java8提供的日期时间均是线程安全的,原始的Data、DateFormat、Calendar等均线程不安全