jdk8笔记

lambda表达式:
个人见解主要用于使用匿名内部使使用用于省略类名,只保留内部方法的参数和方法体。
这种做法使代码更加整洁美观。

也可用于其他接口,但是实现的方法只能有一个,对于没有方法,或者多个方法的接口无法使用。
​ Lambda是一个匿名函数,可以理解为一段可以传递的代码(将代码像数据一样传递);
可以写出更简洁、更灵活的代码;作为一种更紧凑的代码风格,是Java语言表达能力得到提升。
lambda表达式必须要是函数式接口,可以用 @FunctionalIterface检查

泛型 u
第一个不能删除。删除的话,编译器会认为你的方法返回一个名称为U的类(U.class),会找不到。
这个就是用来告诉编译器,我这里要返回一个泛型,不用管我
@Test
public void test01(){
//匿名内部类
Comparator comparator = new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}

    @Override
    public boolean equals(Object obj) {
        return false;
    }
};
//调用
TreeSet<Integer> set = new TreeSet<>(comparator);

}
使用lambda表达式:
@Test
public void test02(){
// Lambda 表达式
Comparator comparator = (a, b) -> Integer.compare(a, b);

TreeSet<Integer> set = new TreeSet<>(comparator);

}
演变过程:

  • 垃圾代码 --> 策略模式 --> 匿名内部类 --> Lambda表达式
    基础语法:
  • 操作符:->
  • 左侧:参数列表
  • 右侧:执行代码块 / Lambda 体
    口诀:

写死小括号,拷贝右箭头,落地大括号
左右遇一括号省
左侧推断类型省
语法格式:

无参数,无返回值:() -> sout
例如 Runnable接口:
public class Test02 {
int num = 10; //jdk 1.7以前 必须final修饰

@Test
public void test01(){
    //匿名内部类
    new Runnable() {
        @Override
        public void run() {
            //在局部类中引用同级局部变量
            //只读
            System.out.println("Hello World" + num);
        }
    };
}

@Test
public void test02(){
    //语法糖
 	Runnable runnable = () -> {
     	System.out.println("Hello Lambda");
 	};
}

}
有一个参数,无返回值
@Test
public void test03(){
Consumer consumer = (a) -> System.out.println(a);
consumer.accept(“我觉得还行!”);
}

有一个参数,无返回值 (小括号可以省略不写)
@Test
public void test03(){
Consumer consumer = a -> System.out.println(a);
consumer.accept(“我觉得还行!”);
}
有两个及以上的参数,有返回值,并且 Lambda 体中有多条语句
@Test
public void test04(){
Comparator comparator = (a, b) -> {
System.out.println(“比较接口”);
return Integer.compare(a, b);
};
}
有两个及以上的参数,有返回值,并且 Lambda 体中只有1条语句 (大括号 与 return 都可以省略不写)
@Test
public void test04(){
Comparator comparator = (a, b) -> Integer.compare(a, b);
}
Lambda 表达式 参数的数据类型可以省略不写 Jvm可以自动进行 “类型推断”
函数式接口:

接口中只有一个抽象方法的接口 @FunctionalIterface
测试:

定义一个函数式接口:
@FunctionalInterface
public interface MyFun {

Integer count(Integer a, Integer b);

}

@Test
public void test05(){
MyFun myFun1 = (a, b) -> a + b;
MyFun myFun2 = (a, b) -> a - b;
MyFun myFun3 = (a, b) -> a * b;
MyFun myFun4 = (a, b) -> a / b;
}
public Integer operation(Integer a, Integer b, MyFun myFun){
return myFun.count(a, b);
}

@Test
public void test06(){
Integer result = operation(1, 2, (x, y) -> x + y);
System.out.println(result);
}

函数式接口
Java内置四大核心函数式接口:

函数式接口 参数类型 返回类型 用途
Consumer
消费型接口 T void 对类型为T的对象应用操作:void accept(T t)
Supplier
提供型接口 无 T 返回类型为T的对象:T get()
Function<T, R>
函数型接口 T R 对类型为T的对象应用操作,并返回结果为R类型的对象:R apply(T t)
Predicate
断言型接口 T boolean 确定类型为T的对象是否满足某约束,并返回boolean值:boolean test(T t)

消费型接口
@Test
public void test01(){
//Consumer
Consumer consumer = (x) -> System.out.println(“消费型接口” + x);
//test
consumer.accept(100);
}
提供型接口
@Test
public void test02(){
List list = new ArrayList<>();
List integers = Arrays.asList(1,2,3);
list.addAll(integers);
//Supplier
Supplier supplier = () -> (int)(Math.random() * 10);
list.add(supplier.get());
System.out.println(supplier);
for (Integer integer : list) {
System.out.println(integer);
}
}
函数型接口
@Test
public void test03(){
//Function<T, R>
String oldStr = “abc123456xyz”;
Function<String, String> function = (s) -> s.substring(1, s.length()-1);
//test
System.out.println(function.apply(oldStr));
}
断言型接口
@Test
public void test04(){
//Predicate
Integer age = 35;
Predicate predicate = (i) -> i >= 35;
if (predicate.test(age)){
System.out.println(“你该退休了”);
} else {
System.out.println(“我觉得还OK啦”);
}
}
总结:
以上接口比较常用,消费型有参数没有返回值
提供型,没有参数有返回值
函数型有参数有返回值
断言型有参数,返回布尔类型
其他接口:
BiFunction<T,U,R>等


方法引用
**定义:**若 Lambda 表达式体中的内容已有方法实现,则我们可以使用“方法引用”
前置条件 Lambda 表达实体中调用方法的参数列表、返回类型必须和函数式接口中抽象方法保持一致
语法格式:

对象 :: 实例方法
类 :: 静态方法
类 :: 实例方法

对象::实例方法
lambda体中的方法已经有方法完成的时候,接口中的抽象方法的参数列表,和、返回值类型,必须与方法体中的方法保持一致。
public interface Consumer {

void accept(T t);
}
public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

@Test
public void test01(){
PrintStream ps = System.out;
Consumer con1 = (s) -> ps.println(s);
con1.accept(“aaa”);

Consumer<String> con2 = ps::println;
con2.accept("bbb");

}

类::静态方法
lamda体中的参数类型和返回值,跟函数式接口中抽象方法保持一致
@Test
public void test02(){
Comparator com1 = (x, y) -> Integer.compare(x, y);
System.out.println(com1.compare(1, 2));

Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(2, 1));

}

类::实例方法
@Test
public void test03(){
BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);
System.out.println(bp1.test(“a”,“b”));

BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp2.test("c","c"));

}
**条件:**Lambda 参数列表中的第一个参数是方法的调用者,第二个参数是方法的参数时,
才能使用 ClassName :: Method

构造器引用
格式:

ClassName :: new
@Test
public void test04(){
Supplier sup1 = () -> new ArrayList();

Supplier<List> sup2 = ArrayList::new;

}

数组引用
语法:

Type :: new;

mybtisplus中的
Article::getId
相当于
Article article=new Article();
article.


stream流:
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一
个则是 Stream API(java.util.stream.*)。
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对
集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数
据库查询。也可以使用 Stream API 来并行执行操作。简而言之,
Stream API 提供了一种高效且易于使用的处理数据的方式

流(Stream) 到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 “集合讲的是数据,流讲的是计算!”
注意: ①Stream 自己不会存储元素。 ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream 的操作三个步骤
⚫ 创建 Stream
一个数据源(如:集合、数组),获取一个流
⚫ 中间操作
一个中间操作链,对数据源的数据进行处理
⚫ 终止操作(终端操作)
一个终止操作,执行中间操作链,并产生结果
创建Stream
Java8 中的 Collection 接口被扩展,提供了
两个获取流的方法: ⚫ default Stream stream() : 返回一个顺序流(串行流)
⚫ default Stream parallelStream() : 返回一个并行流
List list=new ArrayList<>();
Stream stream1=list.stream();
由数组创建流
Java8 中的 Arrays 的静态方法 stream() 可
以获取数组流: ⚫ static Stream stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组: ⚫ public static IntStream stream(int[] array)
⚫ public static LongStream stream(long[] array)
⚫ public static DoubleStream stream(double[] array)
Employee[] emps=new Employee[10];
Stream stream2=Arrays.stream(emps);
由值创建流
可以使用静态方法 Stream.of(), 通过显示值
创建一个流。它可以接收任意数量的参数。 ⚫ public static Stream of(T… values) : 返回一个流
Stream.of(“aa”,“bb”,“cc”)
由函数创建流:创建无限流
可以使用静态方法 Stream.iterate() 和
Stream.generate(), 创建无限流。
⚫ 迭代
public static Stream iterate(final T seed, final
UnaryOperator f)
Stream.iterate(0,(x)->x+2);
⚫ 生成
public static Stream generate(Supplier s) :

原理:数据源:集合,数组经过一系列流水线的操作,产生了一个新流,不会对原数据产生影响。

Stream 的中间操作
方 法 描 述
filter(Predicate p) 接收 Lambda , 从流中排除某些元素。
distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去
除重复元素
limit(long maxSize) 截断流,使其元素不超过给定数量。
skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素
不足 n 个,则返回一个空流。与 limit(n) 互补
多个中间操作可以连接起来形成一个流水线,除非流水
线上触发终止操作,否则中间操作不会执行任何的处理!
而在终止操作时一次性全部处理,称为“惰性求值”。
筛选与切片

方 法 描 述
filter(Predicate p) 接收 Lambda , 从流中排除某些元素。
distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去
除重复元素
limit(long maxSize) 截断流,使其元素不超过给定数量。
skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补

Stream 的中间操作
映射
方 法 描 述
map(Function f) 接收一个函数作为参数,该函数会被应用到每个元
素上,并将其映射成一个新的元素。
mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元
素上,产生一个新的 DoubleStream。
mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元
素上,产生一个新的 IntStream。
mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元
素上,产生一个新的 LongStream。
flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另
一个流,然后把所有流连接成一个流

Stream 的中间操作
排序
方 法 描 述
sorted() 产生一个新流,其中按自然顺序排序
sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序

Stream 的终止操作
终端操作会从流的流水线生成结果。其结果可以是任何不是流的
值,例如:List、Integer,甚至是 void 。
查找与匹配
方 法 描 述
allMatch(Predicate p) 检查是否匹配所有元素
anyMatch(Predicate p) 检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
Stream 的终止操作
方 法 描 述
count() 返回流中元素总数
归约
reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。 返回 T
reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。
返回 Optional
备注:map 和 reduce 的连接通常称为map-reduce 模式,因 Google 用它
来进行网络搜索而出

收集
方 法 描 述
collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的
实现,用于给Stream中元素做汇总的方法
Collector 接口中方法的实现决定了如何对流执行收集操作(如收
集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态
方法,可以方便地创建常见收集器实例,具体方法与实例如下表:
方法 返回类型 作用
toList List 把流中元素收集到List
List emps= list.stream().collect(Collectors.toList());
toSet Set 把流中元素收集到Set
Set emps= list.stream().collect(Collectors.toSet());
toCollection Collection 把流中元素收集到创建的集合
Collectionemps=list.stream().collect(Collectors.toCollection(ArrayList::new));
counting Long 计算流中元素的个数
long count = list.stream().collect(Collectors.counting());
summingInt Integer 对流中元素的整数属性求和
inttotal=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingInt Double 计算流中元素Integer属性的平均

doubleavg= list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingInt IntSummaryStatistics 收集流中Integer属性的统计值。 如:平均值
IntSummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joining String 连接流中每个字符串
String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxBy Optional 根据比较器选择最大值
Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minBy Optional 根据比较器选择最小值
Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing 归约产生的类型 从一个作为累加器的初始值
开始,利用BinaryOperator与
流中元素逐个结合,从而归
约成单个值
inttotal=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
collectingAndThen 转换函数返回的类型 包裹另一个收集器,对其结
果转换函数
inthow= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingBy Map<K, List> 根据某属性值对流分组,属
性为K,结果为V
Map<Emp.Status, List> map= list.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
partitioningBy Map<Boolean, List> 根据true或false进行分区
Map<Boolean,List>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage));

并行流与串行流
并行流就是把一个内容分成多个数据块,并用不同的线程分
别处理每个数据块的流。
Java 8 中将并行进行了优化,我们可以很容易的对数据进行并
行操作。Stream API 可以声明性地通过 parallel() 与
sequential() 在并行流与顺序流之间进行切换。

Fork/Join 框架与传统线程池的区别
采用 “工作窃取”模式(work-stealing):
当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线
程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。
相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的
处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因
无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果
某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子
问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程
的等待时间,提高了性能

Optional 类
Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,
原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且
可以避免空指针异常。
常用方法:
Optional.of(T t) : 创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional

重复注解与类型注解
Java 8对注解处理提供了两点改进:可重复的注解及可用于类
型的注解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值