更快更好
集合结构、jvm等优化。
Lambda
简写函数式接口的匿名内部类。使得内部类可以像数据一样传输至函数的参数。策略设计模式,可以跟stream结合。
jdk8内置四大核心函数式接口
省的每次都创建函数式接口,对于入参和返回值不同情况,主要提供4大内置接口,还有其他接口。
stream api中的方法参数主要就是这四大接口。
public void happy(double money, Consumer<Double> con){
con.accept(money);
}
//消费型接口Consumer<T> void accept(T t);
@Test
public void test1(){
happy(1000,(m) -> System.out.println("每次消费"+m+"元"));
}
//产生指定个数整数加入集合
public List<Integer> getNumList(int num, Supplier<Integer> sup){
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0;i<num;i++){
Integer n = sup.get();
list.add(n);
}
return list;
}
//供给型接口Supplier<T> T get();
@Test
public void test2(){
List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));
for (Integer integer : numList) {
System.out.println(integer);
}
}
//函数型接口Function<T, R> R apply(T t);
@Test
public void test3(){
String s = strHandler(" tesettsets ", (str) -> str.trim());
System.out.println(s);
}
//处理字符串
public String strHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
//断言型接口Predicate<T> boolean test(T t);
@Test
public void test4(){
List<String> list = Arrays.asList("hello","de","lambda");
List<String> strList = filterStr(list, (s) -> s.length() > 3);
for (String s : strList) {
System.out.println(s);
}
}
//将满足条件字符串,放入集合中
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String s : list) {
if (pre.test(s)){
strList.add(s);
}
}
return strList;
}
方法引用
对象::方法
类::静态方法
类::实例方法名 String::equals
构造器引用 String[]::new
进一步简化lambda,需要参数和返回值类型都一致。
Stream API
对集合进行数据传输处理。产生一个新流,stream不会存储对象。
集合是数据,流是计算。
类似sql语句条件。
Stream操作的三个步骤:
- 创建Stream
- 中间操作
- 终止操作
创建
public class TestStream {
//创建Stream
@Test
public void test1(){
//1.Collection系列集合提供的串行流stream() 或 并行流parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2.通过Arrays 中的静态方法stream(t)获得数组流
int[] a = new int[10];
IntStream stream2 = Arrays.stream(a);
//3.通过Stream中的静态方法of(可变参数T... value)
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
//4.创建无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream.generate(()->Math.random())
.limit(5)
.forEach(System.out::println);
}
}
中间操作
中间操作需要终止操作触发,多个中间操作会在终止操作执行后全部处理,这称位"惰性求值",延迟加载。
筛选与切片
public class TestStream2 {
List<String> list = Arrays.asList(
"test1",
"setset",
"setset",
"2",
"1"
);
//中间操作
//筛选与切片filter
@Test
public void test1() {
list.stream()//创建
.filter((e) -> e.length() > 2)//中间操作不会有结果,延迟加载
.forEach(System.out::println);//终止操作
}
//limit截断流
@Test
public void test2() {
list.stream()//创建
.filter((e) -> {
System.out.println("短路");
return e.length() > 1;
})
.limit(1)//找到结果就不再执行,不会全输出"短路"
.forEach(System.out::println);//终止操作
}
//skip 扔掉前几个,跟limit相反,但是还会输出短路
@Test
public void test3() {
list.stream()//创建
.filter((e) -> {
System.out.println("短路");
return e.length() > 1;
})
.distinct()//找到结果就不再执行,不会全迭代
.forEach(System.out::println);//终止操作
}
//distinct筛选通过hashcode和equals去除重复元素,对象需要重写hashcode,equals
//也会输出"短路"
@Test
public void test4() {
list.stream()//创建
.filter((e) -> {
System.out.println("短路");
return e.length() > 1;
})
.skip(1)//找到结果就不再执行,不会全迭代
.forEach(System.out::println);//终止操作
}
}
映射
//映射
//map-接收一份Function接口的lambda,该方法会被应用到集合每个元素上
//该方法可以是自己定义
@Test
public void test5(){
list.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
}
//flatMap
//如果map中方法是自己定义返回一个Stream对象,就会得到Stream<Stream<String>>
// 那么普通遍历就需要两次
//flatMap把流集合整合成一个流,只需要一次遍历就可,类似于list中add和addall的区别
排序
//排序
//sorted自然排序Comparable
//定制排序
@Test
public void test6(){
list.stream()
.sorted()
.forEach(System.out::println);
list.stream()
.sorted((e1,e2)->e2.length()-e1.length())
.forEach(System.out::println);
}
终止操作
查找与匹配
public class TestStream3 {
/*
终止操作
*/
List<String> list = Arrays.asList(
"test1",
"setset",
"setset",
"2",
"1"
);
/*
allMatch是否所有元素都匹配该规则
anyMatch是否有一个元素匹配
noneMatch是否没有匹配所有元素
findFirst返回第一个元素的Optional,避免空指针
findAny返回任意元素
count元素总个数
max(t)按条件获取最大值
min(t)
forEach(Consumer c)内部迭代
*/
@Test
public void test1(){
boolean b = list.stream()
.allMatch((e) -> e.length() > 1);
System.out.println(b);
b = list.stream()
.anyMatch((e) -> e.length() > 1);
System.out.println(b);
b = list.stream().noneMatch((e) -> e.length() > 1);
Optional<String> first = list.stream().findFirst();
Optional<String> any = list.stream().findAny();
System.out.println(first+","+any);
}
}
规约
/**
* 规约reduce(起始值,规约)
*/
@Test
public void test3(){
List<Integer> list = Arrays.asList(1,2,3,4,5);
Integer reduce = list.stream().reduce(2, (x, y) -> x + y);
System.out.println(reduce);
}
收集
//收集collect需要Collects工具类
@Test
public void test4(){
Set<String> collect = list.stream()
.filter((x)->x.length()>3)
.map(String::toUpperCase)
.collect(Collectors.toSet());
collect.forEach(System.out::println);
}
并行流与顺序流
取代Fork/Join框架,(将大任务拆分成若干个小任务)。
parallel()。极大利用占用cpu。工作窃取,一个线程执行完了,会去偷其他线程的任务执行。
接口默认方法与静态方法
//也能使用函数式接口声明
@FunctionalInterface
public interface Test {
default String getName(){
return "test";
}
void test();
}
新日期API
传统日期是可变对象,不安全,使用麻烦。
新日期不可变,就是不能new。
public class NewDate {
//读取本地时间LocalDate LocalTime LocalDateTime
@Test
public void test1(){
LocalDateTime now = LocalDateTime.now();
System.out.println(now);//2021-02-05T20:59:12.507
System.out.println(LocalDateTime.of(2015,
10, 19, 13,
22, 33));//2015-10-19T13:22:33
System.out.println(now.plusYears(2));//2023-02-05T21:00:42.804
now.getYear();
}
//时间戳 Instant 以1970年1月1日00:00:00到某个时间的毫秒值
@Test
public void test2(){
Instant now = Instant.now();
System.out.println(now.atOffset(ZoneOffset.ofHours(8)));//2021-02-05T21:04:27.776+08:00
//毫秒值
System.out.println(now.toEpochMilli());//1612530325402
}
//Duration 计算两个时间间隔
//Preiod 计算俩个日期之间的间隔
@Test
public void test3() throws InterruptedException {
Instant now = Instant.now();
Thread.sleep(1000);
Instant now1 = Instant.now();
Duration between = Duration.between(now, now1);
System.out.println(between.toMillis());
System.out.println("--------------");
LocalDate t1 = LocalDate.now();
Thread.sleep(1000);
LocalDate t2 = LocalDate.now();
Period between1 = Period.between(t1, t2);
System.out.println(between1.getYears());
}
}
//时间矫正器TemporalAdjusters
@Test
public void test5(){
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
LocalDateTime ldt2 = ldt.withDayOfMonth(10);
System.out.println(ldt2);
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3);
}
//格式化时间DateTimeFormatter
@Test
public void test6(){
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt.format(dtf));
System.out.println("----------");
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH:mm:ss");
System.out.println(ldt.format(dtf2));
}
重复注解与类型注解
public class TestAnn {
private @NonNull String a = "2";
@MyAnn("hello")
@MyAnn("hello2")//注解数据类型类似@NonNull
public void show(@MyAnn("abs") String str){
}
@Test
public void test1() throws Exception{
Class<TestAnn> c1 = TestAnn.class;
Method m1 = c1.getMethod("show");
MyAnn[] mas = m1.getAnnotationsByType(MyAnn.class);
for (MyAnn ma : mas) {
System.out.println(ma.value());
}
}
}
@Repeatable(MyAnns.class)
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.PARAMETER,ElementType.TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnn{
String value() default "默认";
}
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.PARAMETER,ElementType.TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnns{
MyAnn[] value();
}