大纲
- Lambda 表达式
- FP(函数式编程)
- 日期和时间库
- 杂项
Lambda 表达式
Lambda 表达式说明
- Lambda 表达式是一个带有参数的代码块。
- Lambda 表达式是一段可以传递的代码。
- Lambda 表达式可以被转换为函数式接口。
- Lambda 表达式可以在闭包作用域中有效的访问final变量。
Java Lambda 示例
定义一个lambda
Predicate<String> notNull1 = (s) -> {
return Objects.nonNull(s);
};
Predicate<String> notNull2= s -> Objects.nonNull(s);
Method Reference(方法引用)
Predicate<String> notNull3= Objects::nonNull;
直接传递lambda表达式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("new thread run !");
}
}).start();
new Thread(()-> System.out.println("new thread run !")).start();
函数式接口指的是拥有
@FunctionalInterface
注解的接口。
package java.lang;
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
变量作用域
int outer = 0;
@Test
public void testVar() throws Exception {
int local = 0;//隐式为final
int old=outer;
Runnable run = () -> {
System.out.println(local);//可以调用
System.out.println(outer);//可以调用
//local++; 编译错误,无法改变local的值
outer++;//可以更改
};
run.run();
Assert.assertEquals(old + 1, outer); //通过
}
反向排序
List<Integer> list = Arrays.asList(10, 20, 1, 22, 33);
Collections.sort(list, (o1, o2) -> Integer.compare(o2, o1));
延迟执行
logger.info("x: "+x+", y: "+y+", student: "+student.toString());
logger.info(()->"x: "+x+", y: "+y+", student: "+student.toString());
方法引用用于sql查询
sqlManager.lambdaQuery(Device.class)
.andEq(Device::getDevNo, devno)
.andEq(Device::getDeleteFlag, AppConst.YesOrNo.no)
.single();
FP(函数式编程)
stream 相关API
- 新增包
java.uti.stream
。 java.util.Collection
、java.util.Map
等接口增加相关方法。- 一些通用的FunctionalInterface(函数式接口)。下面列出只是部分。
java.util.function.Supplier
java.util.function.Function
java.util.function.BiFunction
java.util.function.Predicate
java.util.function.BiPredicate
java.util.function.Consumer
java.util.function.BiConsumer
接口默认方法
Java8 在原有的Collection和Map等接口中增加了新的方法。会导致对旧程序不兼容。 比如你写了一个QuickMap,实现了旧的Map接口。Java8在Map接口中增加了新方法,但QuickMap并没有实现它们。
为了向前兼容,Java8在语言层面增肌了新特性,那就是接口默认方法。 针对我们刚才举例的情况,Java8是这么解决的,代码如下:
package java.util;
public interface Map<K,V> {
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
......
}
Stream 关键方法
- filter 过滤
- map 转换
- flatMap 展开并转换
- collect 收集stream中的数据
- reduce 聚合操作
Stream 示例代码
取字符串列表中,不为空的,小写的,每个字符串的开头和末尾两个字符,组成新的列表。
List<String> wordList = Arrays.asList("Hello","", "WOrld", "Lily", "and"," ", "Han");
List<Character> charList = wordList.stream()
.filter(w -> w != null && w.trim().length() >= 2)
.map(w -> w.toLowerCase()) // .map(String::toLowerCase);
.flatMap(w -> Stream.of(w.charAt(0), w.charAt(w.length() - 1)))
.collect(Collectors.toList());
通过账号列表获取逗号分隔的id列表
List<Account> accountList = ... ;
String ids = accountList.stream()
.map(Account::getId)
.collect(Collectors.joining(","));
通过账号列表,获取id到username的映射
Map<String, String> idToName = accountList.stream()
.collect(Collectors.toMap(Account::getId, Account::getUsername));
账号按部门分组
List<Account> accountList = ... ;
Map<String, List<Account>> depWithAccountList = accountList.stream()
.filter(a -> a.getDepId() != null)
.collect(Collectors.groupingBy(Account::getDepId));
计算和
List<Integer> nums = Arrays.asList(1, 3, 4, 6, 2, 3, 1);
Integer sum = nums.stream().reduce(0, (x, y) -> x + y);
Optional<Integer> sum2 = nums.stream().reduce((x, y) -> x + y);
int sum3 = nums.stream().mapToInt(Integer::intValue).sum();
日期和时间库
java.time
包
java.time.Instant
时间线上的一个时间点.java.time.Duration
两个时间点之间间隔.java.time.LocalDateTime
日期时间,与时区无关。java.time.ZonedDateTime
日期时间,与时区关联。
示例代码
获取当前毫秒值
Instant.now().toEpochMilli()
打印当前日期时间
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();//instant + offset
System.out.println(dateTimeFormatter.format(now));
ZonedDateTime now1 = ZonedDateTime.now();//instant + zone
System.out.println(dateTimeFormatter.format(now1));
Instant
|LocalDateTime
|ZonedDateTime
之间转换
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.now(),
ZoneId.systemDefault());
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(Instant.now(),
ZoneId.systemDefault());
ZonedDateTime zonedDateTimeTmp = LocalDateTime.now().atZone(ZoneId.systemDefault());
Instant instant = zonedDateTimeTmp.toInstant();
与Date的转换
Date from = Date.from(Instant.now());
Instant instant = new Date().toInstant();
杂项
String自带join
String join = String.join(",", "1", "3", "4");
String join1 = String.join(",", Arrays.asList("2", "3", "6"));
String join2 = String.join(",", new String[]{"1", "2", "3"});
System.out.println(join);
System.out.println(join1);
System.out.println(join2);
Optional 可选值
Random r = new Random();
Optional<String> val = Optional.ofNullable(r.nextBoolean() ? null : "1");
//不为空时才处理
val.ifPresent(v -> {
String line = v + "hello";
System.out.println(line);
});
//不为空则转换为int,为空则返回-1
Integer number = val.map(Integer::parseInt).orElse(-1);
Optional<Object> empty = Optional.empty();
文件操作 (Java7开始)
按行读取文本文件内容
try(Stream<String> lines= Files.lines(Paths.get("test.txt"))){
List<String> collect = lines.filter(Texts::hasText)
.collect(Collectors.toList());
}
遍历目录,包含子目录。深度优先遍历
try (Stream<Path> entries = Files.walk(Paths.get("rootDir"))) {
//打印文件名
entries.map(Path::getFileName)
.peek(System.out::println);
}
java.util.Objects (Java7开始)
- Objects#equals
- Objects#deepEquals
- Objects#hashCode
- Objects#toString
- Objects#compare
- Objects#requireNonNull
- Objects#isNull
- Objects#nonNull
- ......