博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
每日一学:lambda 表达式,Stream 流操作,Optional 可空类型,LocalDate 日期类型
阅读量:3734 次
发布时间:2019-05-22

本文共 8892 字,大约阅读时间需要 29 分钟。

lambda 表达式

  1. lambda 表达式,用来进一步简化匿名类的语法,不需要提供类名和方法定义,使用:(参数) -> 结果,就可以构造出接口实例,所有函数式接口(即仅有一个抽象方法的接口)上均可运用,接口加上 @FunctionalInterface 修饰;
new Thread(new Runnable(){
@Override public void run(){
System.out.println("hello1");}}).start();Arrays.sort(people,(p1,p2)->p1.age-p2.age);
  1. 在 java.util.function 包中定义了各种函数式接口,如:用于提供数据的 Supplier 接口,只有一个 get 抽象方法,没有入参,有一个返回值,通过 get 获取对象;
@FunctionalInterface	public interface Supplier
{
T get(); }Supplier
random = ()->ThreadLocalRandom.current().nextInt();如:使用 supplier 来获取随机数 random.get();
  1. Predicate 接口,抽象方法 test,入参是泛型 T ,返回布尔值,用做条件判断,并且还定义了几个默认方法 and,or,negate 来组合 predicate 条件,static 方法 isEqual 返回判断与入参 targetRef equal 的 predicate 实例;
@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));
  1. Function<T,R> 接口,其抽象方法 R apply(T t),接收一个入参,返回一个结果,其默认方法 compose 返回 function 接口,先执行入参 before 的 apply,然后执行自身的 apply,andThen 与 compose 相反,
R apply(T t);  default 
Function
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"));
  1. BiFunction<T,U,R> 接口,和 Function 接口类似,其 apply 方法,接受两个入参,返回一个结果,默认的 andThen 方法提供多个 BiFunction 的组合;
R apply(T t, U u);default 
BiFunction
andThen(Function
after) {
return (T t, U u) -> after.apply(apply(t, u)); }
  1. Lambda 表达式,使用简短的代码实现方法的定义,代码复用更方便,可将一大段逻辑中变化的部分,抽象出函数式接口,由外部方法提供函数实现,不过在自定义函数式接口前,可以先确认下 java.util.function 包中的 43 个标准函数式接口是否能满足需求;

Stream 流操作

  1. Stream 流操作,是将集合的投影,转换,过滤等操作抽象成函数式接口,通过传入 Lambda 的实现,完成具体操作,如 filter 实现过滤,map 实现转换;
.stream().filter(i->i>20).map(i->i*i).sorted().limit(10).max()
  1. 流式操作,将集合的一些常见操作,遍历查找,遍历映射,排序,去重等,统一用流 stream 来操作,并且可以实现并行运算 .parallelStream();
 
  1. Stream 的 filter 和 map 用来筛选数据和转换数据;

  2. map 方法传入一个 Function,实现对象转换;filter 方法传入一个 Predicate,实现对象的布尔判断,只保留返回 true 的数据;mapToDouble 用于把对象转换为 double;通过 average 方法返回一个 OptionalDouble,表示一个可为空的 double;

List
ints = 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 方法,有带有实现的方法;

Optional 可空类型

  1. Optional 类,可以避免使用 Stream 进行级联调用时的空指针问题,并且提供了一些实用的方法来实现判空逻辑;

LocalDate 日期类型

  1. 提供了全新的时间类,LocalDateTime,LocalDate,LocalTime,和 DateTimeFormatter;

Tips:

  1. Java程序中只要有一个非Daemon线程没有结束,那么整个程序是不会退出的;

  2. sleep() 休眠,不会释放锁,wait() 会释放锁,interupt() 添加中断标志,并不一定能使线程立即响应中断;

  3. 如果 new FileInputStream(fileName) 无法找到文件,可以使用 getClassLoader().getResourceAsStream(fileName) 来替代;

基础类

  1. Scanner,从数据源获取数据并解析,数据源有文件,输入流,字符串等;
// 是否有下一个输入项	hasNextXXX(),hasNextLine()	// 获取下一个输入,下一行	nextXXX(),nextLine()
  1. Object,所有类的隐式父类,有 wait,notify,clone 方法,Objects,是对象工具类,有很多空指针安全的方法
// obj 为 null 时,输出 "null"	Objects.toString(obj)
  1. String,创建后不可改变,赋值操作,是新创建了一个字符串对象,并将引用指向新对象,+ 操作,同样会创建新对象,字符串常量,保存在方法区的常量池,对象比较,应该使用 equals,StringBuffer 和 StringBuilder,均是内容可变的字符串对象,不会新创建 String 对象,其中 StringBuffer 是线程安全的;
// 指向方法区常量池	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)
  1. Random,ThreadLocalRandom,都可以用来产生伪随机数,ThreadLocalRandom 更适合在多线程下使用,伪随机数,是指值是根据种子产生的,相同的种子,以同样的顺序,产生的随机数是一致的;

  2. BigDecimal,用于浮点数计算,不会有精度缺失的问题,建议构造中传入字符串类型的浮点数,

// 推荐第二种	new BigDecimal(0.1)     	new BigDecimal("0.1")
  1. Properties,key-value 形式的属性列表,有 load(Inputstream is) 和 store(OutputStream os),将 properties 内容和 stream 进行转换;

  2. 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());
  1. System 和 Runtime,System 的 getProperties(),getenv(),用来获取系统环境变量和属性,Runtime,可以获取 jvm 的相关信息,通过 Runtime.getRuntime() 来获取实例;

  2. 格式化类 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());

Java 数组

  1. 引用类型,存放在堆区,构造时要求指定数组长度且不可变,构造时内存已经完成分配,每个数组元素均有默认值;
// 堆中分配一块连续内存,每一块值分别为 1,2,3,且栈中变量 intArr 指向堆区位置	int[] intArr = [1,2,3]	// 堆中分配一块连续内存,值是 null,栈中分配一个引用变量,指向堆中数组	String[] strArr = new String[3]
  1. Java 中没有多维数组,只有一维数组,所谓的多维数组,其实是一维数组,数组中每个元素都是一个新数组,且不要求长度一致;

  2. java.util.Arrays,提供了排序 sort(),要求数组元素实现 Comparable 接口,或者 sort 参数,传入一个 Comparable 接口的实现类,对基本类型的数组,采用的是优化的快排,对引用类型的数组,采用的是改进的归并排序;

  3. Arrays 还提供了,对排序数组的二分查找 binarySearch(),返回元素所在位置,如果返回负数,代表数组中没有该元素,且该元素应该插入的位置,来继续保证有序;

    Arrays,数组工具类,

  4. 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();

Set 和 Map

  1. HashSet 和 HashMap,本质上 HashSet 是 value为new Object() 的 HashMap 实现的,而 HashMap 底层是一个动态数组,数组中每一项值是 Map.Entry<key,value> 的链表,数组的初始大小是16,默认负载因子是0.75,表示当数组存放元素达到10 时,会触发数组扩容,容量翻倍;

  2. HashMap 的 put 方法,首先会计算出 key 的 hashCode,然后对数组长度取余,获取其存放数组的下标位置,并判断该位置是否已经有对象,且 key 值是否相等,equals 判断相等,如果相等,覆盖其 value,否则与已有元素组成链表,链表头是刚放入的元素,最后进行扩容判断;

  3. 所以 HashMap 是无序,无重复 key,插入和获取效率高,元素冲突,反复扩容,都涉及数组复制,对性能影响大,不太适合容量反复变化的场景,对于 map 容量有规划的场景,建议直接指定初始容量,初始容量会取大于构造参数的 2^n 的最小值,这个值可以用右移代替除法操作,同时负载因子越大,扩容越滞后,占用空间越小,哈希冲突越高;

  4. 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); }
  1. TreeSet 和 TreeMap,同样 TreeSet 本质,也是 value 为 new Object() 的 TreeMap 来实现的,是一种红黑树结构的有序集合,可以指定比较逻辑,默认是自然比较;

  2. LinkedHashMap,仅在 hashMap 的基础上,给元素 entry 添加了一个 before 和 after 的指针,维护了一个添加顺序;

List

  1. ArrayList,底层是可变数组,如果在指定索引处,添加或者删除元素,都需要将数组元素整体向后复制一位,所以效率很低,但读取效率很高;其 add(int index,E ele) 方法,会判断是否超出数组大小,如果超出,需要进行数组扩容 1.5 倍,然后将 index 之后的所有元素整体后移一位,新元素放入 index 位置;

  2. LinkedList,是按添加顺序来保存数据,底层是双向链表,可以灵活实现堆,或栈的结构,其 add(int index, E ele) 方法,首先通过顺序查找,找到 index 处链表元素 entry,然后只需改变该 entry 的前向指针,和该 entry 的前一个元素的后向指针即可,效率很快,只耗费在顺序查找中,同样 remove 方法,效率也很高;

  3. 比较 ArrayList 和 LinkedList,ArrayList 的随机读取效率高,插入和删除效率比较低,而 LinkedList 相反,频繁插入和删除元素,效率高;

  4. Vector 和 Stack,Vector 可以看做是 ArrayList 的线程安全版本,在 ArrayList 的基础上,添加 synchronized 关键字,但由于序列化安全,性能一般等因素,不建议使用,Stack 栈结构,继承自 Vector ,也不推荐使用;

  5. 集合类,往往都实现了 Iterator 迭代器接口,这是一种设计模式,用来遍历集合元素,注意,迭代过程中,可以使用 iterator 的 remove() 来删除元素,不能使用集合类的删除方法,因为这些方法,会改变集合的size,而迭代的 hasNext() 需要通过 size 来判断是否还有元素,就会出现错误;

  6. Collections 工具类,提供了对 set,list,map 的排序,查找等方法;提供了对集合类的二分查找方法:

// 采用的是改进的归并排序	Collections.sort()	// 二分查找,得到其索引,并且只有排序的list才可以使用;	int binarySearch(list,key)	// 对set,list,map 包装成线程安全的集合;	synchronizedXXX()	// 返回一个不可变集合(只读集合);	emptyXXX(),singletonXXX(),unmodifiableXXX()

queue 和 Deque

  1. Queue 队列,队头到队尾,是按照排队时间,有序存放,队列元素先进先出。实现类有 LinkedList,PriorityQueue,注意PriorityQueue 是一个排序后的队列,并不是按加入时间;

  2. Deque 双向队列,可在头尾双向操作,可实现先进后出的栈结构,实现类有 LinkedList;

转载地址:http://bsfin.baihongyu.com/

你可能感兴趣的文章
蓝桥杯真题 17省10-k倍区间 给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i
查看>>
蓝桥杯真题 17省9-分巧克力 儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。 小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。 为了公平起见,小明
查看>>
蓝桥杯 20模1-4-数字9 在1至2019中,有多少个数的数位中包含数字9? 注意,有的数中的数位中包含多个9,这个数只算一次。例如,1999这个数包含数字9,在计算只是算一个数。
查看>>
蓝桥杯真题 18国1-换零钞 x星球的钞票的面额只有:100元,5元,2元,1元,共4种。 小明去x星旅游,他手里只有2张100元的x星币,太不方便,恰好路过x星银行就去换零钱。 小明有点强迫症,
查看>>
蓝桥杯真题 14校3-大小之差
查看>>
蓝桥杯真题 15校1-单词计数 输入一个字符串,求它包含多少个单词。单词间以一个或者多个空格分开。 第一个单词前,最后一个单词后也可能有0到多个空格。 比如:“ abc xyz“ 包含两个单
查看>>
蓝桥杯真题 14省2-切面条 一根高筋拉面,中间切一刀,可以得到2根面条。 如果先对折1次,中间切一刀,可以得到3根面条。 如果连续对折2次,中间切一刀,可以得到5根面条。 那么,连续对折10次,
查看>>
蓝桥杯 算法训练 - 整数平均值
查看>>
蓝桥杯真题 13省2-马虎的算式 小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。 有一次,老师出的题目是:36 x 495 = ? 他却给抄成了:396 x 45 = ? 但结果却
查看>>
蓝桥杯真题 13省3-第39级台阶 小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级! 站在台阶前,他突然又想着一个问题: 如果我每一步只能迈上1个或2个台
查看>>
蓝桥杯真题 15省Ca1-方程整数解 方程: a^2 + b^2 + c^2 = 1000 a2+b2+c2=1000 a^2 + b^2 + c^2 = 1000a2+b2+c2=1000 这个
查看>>
C语言中怎么表示派 -π
查看>>
蓝桥杯 基础训练—闰年判断
查看>>
蓝桥杯 基础训练—十六进制转八进制 输入的第一行为一个正整数n (1<=n<=10)。   接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度
查看>>
蓝桥杯 基础训练—数列排序  给定一个长度为n的数列,将这个数列按从小到大的顺序排列。1<=n<=200
查看>>
蓝桥杯 基础训练—数列特征 给出n个数,找出这n个数的最大值,最小值,和。
查看>>
蓝桥杯 基础训练—特殊的数字 153是一个非常特殊的数,它等于它的每位数字的立方和,即153=1*1*1+5*5*5+3*3*3。编程求所有满足这种条件的三位十进制数。
查看>>
蓝桥杯真题 13省Jb1-世纪末的星期 曾有邪教称1999年12月31日是世界末日。当然该谣言已经不攻自破。 还有人称今后的某个世纪末的12月31日,如果是星期一则会.... 有趣的是,任何一个世
查看>>
蓝桥杯真题 18省1-第几天 2000年的1月1日,是那一年的第1天。 那么,2000年的5月4日,是那一年的第几天?
查看>>
蓝桥杯 14校4-回文数字  观察数字:12321,123321 都有一个共同的特征,无论从左到右读还是从右向左读,都是相同的。这样的数字叫做:回文数字。   本题要求你找到一些5位或6位的十进制
查看>>