本文共 8892 字,大约阅读时间需要 29 分钟。
new Thread(new Runnable(){ @Override public void run(){ System.out.println("hello1");}}).start();Arrays.sort(people,(p1,p2)->p1.age-p2.age);
@FunctionalInterface public interface Supplier{ T get(); }Supplier random = ()->ThreadLocalRandom.current().nextInt();如:使用 supplier 来获取随机数 random.get();
@FunctionalInterface public interface Predicate{ boolean test(T t);default Predicate and(Predicate other) { return (t) -> test(t) && other.test(t); }default Predicate negate() { return (t) -> !test(t);}default Predicate or(Predicate other) { return (t) -> test(t) || other.test(t); }static Predicate isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); }// 组合 predicate 判断是否数值是否大于 0 且是偶数Predicate positiveNumber = i -> i > 0;Predicate evenNumber = i -> i % 2 == 0;assertTrue(positiveNumber.and(evenNumber).test(2));
R apply(T t); defaultFunction compose(Function before) { return (V v) -> apply(before.apply(v)); } default Function andThen(Function after) { return (T t) -> after.apply(apply(t)); }// 先把字符串转换为大写,然后通过 andThen 组合另一个Function,实现字符串复制拼接Function upperCase = s -> s.toUpperCase();Function duplicate = s -> s.concat(s);assertThat(upperCase.andThen(duplicate).apply("test"), is("TESTTEST"));
R apply(T t, U u);defaultBiFunction andThen(Function after) { return (T t, U u) -> after.apply(apply(t, u)); }
.stream().filter(i->i>20).map(i->i*i).sorted().limit(10).max()
Stream 的 filter 和 map 用来筛选数据和转换数据;
map 方法传入一个 Function,实现对象转换;filter 方法传入一个 Predicate,实现对象的布尔判断,只保留返回 true 的数据;mapToDouble 用于把对象转换为 double;通过 average 方法返回一个 OptionalDouble,表示一个可为空的 double;
Listints = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); double average = calc(ints); double streamResult = ints.stream() .map(i -> new Point2D.Double((double) i % 3, (double) i / 3)) .filter(point -> point.getY() > 1) .mapToDouble(point -> point.distance(0, 0)) .average() .orElse(0); assertThat(average, is(streamResult));
5.Lambda、Stream 流操作、并行流(ParallelStream)、Optional 可空类型、新日期时间类型等
9. Java8,接口中可以有 static 方法,有带有实现的方法;Java程序中只要有一个非Daemon线程没有结束,那么整个程序是不会退出的;
sleep() 休眠,不会释放锁,wait() 会释放锁,interupt() 添加中断标志,并不一定能使线程立即响应中断;
如果 new FileInputStream(fileName) 无法找到文件,可以使用 getClassLoader().getResourceAsStream(fileName) 来替代;
// 是否有下一个输入项 hasNextXXX(),hasNextLine() // 获取下一个输入,下一行 nextXXX(),nextLine()
// obj 为 null 时,输出 "null" Objects.toString(obj)
// 指向方法区常量池 String a = "dengh"; String b = "dengh"; // 指向堆区 String c = new String("dengh"); String d = new String("dengh"); // true a == b // false c == d // true,String重写了equals方法 c.equals(d)
Random,ThreadLocalRandom,都可以用来产生伪随机数,ThreadLocalRandom 更适合在多线程下使用,伪随机数,是指值是根据种子产生的,相同的种子,以同样的顺序,产生的随机数是一致的;
BigDecimal,用于浮点数计算,不会有精度缺失的问题,建议构造中传入字符串类型的浮点数,
// 推荐第二种 new BigDecimal(0.1) new BigDecimal("0.1")
Properties,key-value 形式的属性列表,有 load(Inputstream is) 和 store(OutputStream os),将 properties 内容和 stream 进行转换;
Pattern 和 Matcher,正则表达式,String 使用正则,有 match(String regex),replaceAll(String regex,String replment),
split(String regex) 等方法,Pattern 可以提前对正则表达式,进行编译,取得优化的效果;\\ 表示一个\ \w 匹配任意字母,数组,下划线,汉字 \d 匹配数字; // aaaaab 是否匹配正则 a*b Pattern p = Pattern.compile("a*b"); Matcher m = p.matcher("aaaaab"); System.out.println(m.matches());
System 和 Runtime,System 的 getProperties(),getenv(),用来获取系统环境变量和属性,Runtime,可以获取 jvm 的相关信息,通过 Runtime.getRuntime() 来获取实例;
格式化类 MessageFormat,NumberFormat,SimpleDateFormat,DecimalFormat 分别用于字符串,数字,日期,小数的格式化;
//hello dengh!today is 17-4-11 下午3:32 String msg = "hello {0}!today is {1}"; System.out.println(MessageFormat.format(msg,"dengh",Calendar.getInstance().getTime())); // 数值规范化,百分数,货币等等, ¥44.99 NumberFormat nf = NumberFormat.getCurrencyInstance(); String s = nf.format(44.99); Number n = nf.parse(s); //注意:HH指定的是24小时制,hh指定的是12小时制 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); String s = sdf.format(Calendar.getInstance().getTime());
// 堆中分配一块连续内存,每一块值分别为 1,2,3,且栈中变量 intArr 指向堆区位置 int[] intArr = [1,2,3] // 堆中分配一块连续内存,值是 null,栈中分配一个引用变量,指向堆中数组 String[] strArr = new String[3]
Java 中没有多维数组,只有一维数组,所谓的多维数组,其实是一维数组,数组中每个元素都是一个新数组,且不要求长度一致;
java.util.Arrays,提供了排序 sort(),要求数组元素实现 Comparable 接口,或者 sort 参数,传入一个 Comparable 接口的实现类,对基本类型的数组,采用的是优化的快排,对引用类型的数组,采用的是改进的归并排序;
Arrays 还提供了,对排序数组的二分查找 binarySearch(),返回元素所在位置,如果返回负数,代表数组中没有该元素,且该元素应该插入的位置,来继续保证有序;
Arrays,数组工具类,T[] Arrays.copyOf(T[] ori,int newLength) ,用于复制数组,获取指定的长度 newLength,截取或用 null 填充,System.arraycopy(src,beginIndex,dest,beginIndex,length),也提供了数组复制,比 for 循环进行复制,优化了很多;
// 注意,默认的复制的方法都是浅复制,是没有 new 对象,都是复制引用 // 实现深复制,只能内部循环 new 对象,或者在 IO 流中处理一遍 ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(src); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(byteIn); dest = (List) in.readObject();
HashSet 和 HashMap,本质上 HashSet 是 value为new Object() 的 HashMap 实现的,而 HashMap 底层是一个动态数组,数组中每一项值是 Map.Entry<key,value> 的链表,数组的初始大小是16,默认负载因子是0.75,表示当数组存放元素达到10 时,会触发数组扩容,容量翻倍;
HashMap 的 put 方法,首先会计算出 key 的 hashCode,然后对数组长度取余,获取其存放数组的下标位置,并判断该位置是否已经有对象,且 key 值是否相等,equals 判断相等,如果相等,覆盖其 value,否则与已有元素组成链表,链表头是刚放入的元素,最后进行扩容判断;
所以 HashMap 是无序,无重复 key,插入和获取效率高,元素冲突,反复扩容,都涉及数组复制,对性能影响大,不太适合容量反复变化的场景,对于 map 容量有规划的场景,建议直接指定初始容量,初始容量会取大于构造参数的 2^n 的最小值,这个值可以用右移代替除法操作,同时负载因子越大,扩容越滞后,占用空间越小,哈希冲突越高;
HashMap 的 key 可以为 null,其 hashCode 为0,注意重写 equals 方法时,通常需要重写 hashCode,很多集合类方法,会同时使用到两者来判断是否为相同元素;
result 赋一个非零常量,将对象的每一个有意义的域(参与equals的)生成一个散列码c,合并计算出散列码: result = 37 * result + c; equals(): public boolean equals(Object o){ return o instanceOf Type && c1.equals(((Type)o).c1) && c2.equals(((Type)o).c2); }
TreeSet 和 TreeMap,同样 TreeSet 本质,也是 value 为 new Object() 的 TreeMap 来实现的,是一种红黑树结构的有序集合,可以指定比较逻辑,默认是自然比较;
LinkedHashMap,仅在 hashMap 的基础上,给元素 entry 添加了一个 before 和 after 的指针,维护了一个添加顺序;
ArrayList,底层是可变数组,如果在指定索引处,添加或者删除元素,都需要将数组元素整体向后复制一位,所以效率很低,但读取效率很高;其 add(int index,E ele) 方法,会判断是否超出数组大小,如果超出,需要进行数组扩容 1.5 倍,然后将 index 之后的所有元素整体后移一位,新元素放入 index 位置;
LinkedList,是按添加顺序来保存数据,底层是双向链表,可以灵活实现堆,或栈的结构,其 add(int index, E ele) 方法,首先通过顺序查找,找到 index 处链表元素 entry,然后只需改变该 entry 的前向指针,和该 entry 的前一个元素的后向指针即可,效率很快,只耗费在顺序查找中,同样 remove 方法,效率也很高;
比较 ArrayList 和 LinkedList,ArrayList 的随机读取效率高,插入和删除效率比较低,而 LinkedList 相反,频繁插入和删除元素,效率高;
Vector 和 Stack,Vector 可以看做是 ArrayList 的线程安全版本,在 ArrayList 的基础上,添加 synchronized 关键字,但由于序列化安全,性能一般等因素,不建议使用,Stack 栈结构,继承自 Vector ,也不推荐使用;
集合类,往往都实现了 Iterator 迭代器接口,这是一种设计模式,用来遍历集合元素,注意,迭代过程中,可以使用 iterator 的 remove() 来删除元素,不能使用集合类的删除方法,因为这些方法,会改变集合的size,而迭代的 hasNext() 需要通过 size 来判断是否还有元素,就会出现错误;
Collections 工具类,提供了对 set,list,map 的排序,查找等方法;提供了对集合类的二分查找方法:
// 采用的是改进的归并排序 Collections.sort() // 二分查找,得到其索引,并且只有排序的list才可以使用; int binarySearch(list,key) // 对set,list,map 包装成线程安全的集合; synchronizedXXX() // 返回一个不可变集合(只读集合); emptyXXX(),singletonXXX(),unmodifiableXXX()
Queue 队列,队头到队尾,是按照排队时间,有序存放,队列元素先进先出。实现类有 LinkedList,PriorityQueue,注意PriorityQueue 是一个排序后的队列,并不是按加入时间;
Deque 双向队列,可在头尾双向操作,可实现先进后出的栈结构,实现类有 LinkedList;
转载地址:http://bsfin.baihongyu.com/