Java8的新特性.pdf
Lambda表达式
适用于比较简单的结构体。避免匿名内部类定义过多的一种函数式编程思想;
接口中只有一个抽象方法,本质就是作为函数式接口的实例
public class test {
public static void main(String[] args) {
new Thread(new Runnable() { //实现匿名内部类
@Override
public void run() {
for(int i=0;i<5;i++) {
System.out.println("a"+i);
}
}
}).start();
for(int i=0;i<5;i++) {
System.out.println("b"+i);
}
}
}
//jdk8 lambda表达式 一般用于比较简单的线程体
public class test {
public static void main(String[] args) {
new Thread(()->{ //关注线程体
for(int i=0;i<5;i++) { //关注内部的核心代码即可 其它的可以简化
System.out.println("a"+i);
}
}
).start();
for(int i=0;i<5;i++) {
System.out.println("b"+i);
}
}
}
推导过程
interface like{
void lambda();
}
//1 接口实现
class people1 implements like{
@Override
public void lambda() {
System.out.println("快乐");
}
}
public class lambdaTest {
static class people2 implements like{
//2 静态内部类实现
@Override
public void lambda() {
System.out.println("快乐2");
}
}
public static void main(String[] args) {
like l1 = new people1();
like l2 = new people2();
like l3 = new like() {
//3 匿名内部类实现
@Override
public void lambda() {
System.out.println("快乐3");
}
};
like l4 =()->{
//4 lambda表达式实现
System.out.println("快乐4");
};
l1.lambda();
l2.lambda();
l3.lambda();
l4.lambda();
}
}
带参数
interface habb{
void lambda(int a);
}
class people3 implements habb{
@Override
public void lambda(int a) {
}
}
public class lambdatest2 {
public static void main(String[] args) {
habb h1 =(a)->{
System.out.println("快乐"+a);
};
h1.lambda(20);
//简化 只有一个参数 可以省略小括号
habb h2 =a->{
System.out.println("快乐"+a);
};
h2.lambda(30);
//Lambda 体只有一条语句时,return 与大括号若有,都可以省略
habb h3 =a->System.out.println("快乐"+a);
h3.lambda(50);
}
}
函数式接口
如果一个接口中,只声明一个抽象方法,则称为函数式接口
可以在接口上用@FunctionalInterface注解检验声明它是一个函数式接口
Java内置四大核心函数式接口
public class testFunction {
public static void main(String[] args) {
//消费型接口原始写法
happyTime(500, new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("???"+aDouble);
}
});
//消费型接口lambda写法
happyTime(500, money-> System.out.println("???"+money));
List<String> strings = Arrays.asList("a", "b", "ab", "ac");
filterStrs(strings,s -> s.contains("a")).forEach(System.out::println);
}
//消费型接口
public static void happyTime(double money, Consumer<Double> consumer){
consumer.accept(money);
}
List<String> list = Arrays.asList("a,aa,ab,ac,bc");
List<String> list2 = filterStrs(list, s -> s.contains("c"));
//断定型接口
//根据指定的规则过滤字符串 规则由Predicate 的方法决定
public static List<String> filterStrs(List<String> list, Predicate<String> pre){
ArrayList<String> filterList = new ArrayList<>();
for (String s : list) {
if (pre.test(s)) {
filterList.add(s);
}
}
return filterList;
}
}
方法引用和构造器的引用
方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用;
实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的,方法的参数列表和返回值类型保持一致
具体分为如下的三种情况:
对象 :: 非静态方法
类 :: 静态方法
类 :: 非静态方法
public class testFunction2 {
//情况一:对象 :: 实例方法
@Test
public void test1(){
Consumer c1 = str -> System.out.println(str);
c1.accept("hello1");
System.out.println("************");
Consumer c2= System.out::println;
c2.accept("hello2");
}
//Supplier中的T get()
//user中的String getName()
@Test
public void test2() {
user u1 = new user("h", 10000.00);
// 先有对象后再调用
Supplier<String> sup=()->u1.getName();
System.out.println(sup.get());
System.out.println("************");
Supplier<String> sup2=u1::getName;
System.out.println(sup2.get());
}
// 情况二:类 :: 静态方法
//Comparator中的int compare(T t1,T t2)
//Integer中的int compare(T t1,T t2)
@Test
public void test3(){
Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1,t2);
System.out.println(com1.compare(12,21));
System.out.println("*******************");
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(12,3));
}
// 情况三:类 :: 实例方法 (前一个参数作为第二个参数的调用者)
// Comparator中的int comapre(T t1,T t2)
// String中的int t1.compareTo(t2)
@Test
public void test4() {
Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
System.out.println(com1.compare("abc","abd"));
System.out.println("*******************");
Comparator<String> com2 = String :: compareTo;
System.out.println(com2.compare("abd","abm"));
}
//BiPredicate中的boolean test(T t1, T t2);
//String中的boolean t1.equals(t2)
@Test
public void test5() {
BiPredicate<String,String> pre1 = (s1, s2) -> s1.equals(s2);
System.out.println(pre1.test("abc","abc"));
System.out.println("*******************");
BiPredicate<String,String> pre2 = String :: equals;
System.out.println(pre2.test("abc","abd"));
}
}
Stream流
使用 Stream对集合数据进行操作计算,可以执行非常复杂的查找、过滤和映射数据等操作
在Java层面对取到的数据流做处理
注:
Stream 自己不会存储元素
Stream 不会改变源对象。相反,它会返回一个持有结果的新Stream
Stream 操作是延迟执行的。等到需要结果的时候才执行(执行终止操作时才执行中间操作链)
Stream 的操作三个步骤
1 创建 Stream
一个数据源(如:集合、数组),获取一个流
2 中间操作
一个中间操作链,对数据源的数据进行处理
3 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
创建
public class streamTest {
public static List<user> getUsers(){
List<user> list = new ArrayList<>();
list.add(new user("h",10000.00));
list.add(new user("h2",10000.00));
list.add(new user("h3",10000.00));
return list;
}
//创建 Stream方式一:通过集合
@Test
public void test1(){
List<user> users =streamTest.getUsers();
// 返回一个顺序流
Stream<user> stream = users.stream();
// 返回一个并行流
Stream<user> parallelStream = users.parallelStream();
}
//创建 Stream方式二:通过数组
@Test
public void test2(){
int[] arr = new int[]{1,2,3,4,5,6};
//调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
IntStream stream = Arrays.stream(arr);
//自定义类型的数组源
user e1 = new user("m",1000);
user e2 = new user("h",2000);
user[] arr1 = new user[]{e1,e2};
Stream<user> stream1 = Arrays.stream(arr1);
}
//创建 Stream方式三:通过Stream的of()
@Test
public void test3(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
}
//创建 Stream方式四:创建无限流
@Test
public void test4(){
// 迭代
//遍历前10个偶数
Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
// 生成
Stream.generate(Math::random).limit(10).forEach(System.out::println);
Stream.generate(()->random.nextInt(10)).limit(10).forEach(System.out::println);
}
}
中间操作
public static List<user> getUsers(){
List<user> list = new ArrayList<>();
list.add(new user("aaa",10000.00,21));
list.add(new user("bbbb",20000.00,18));
list.add(new user("cc",30000.00,29));
return list;
}
#筛选与切片
@Test
public void test5(){
Stream<user> stream = streamTest.getUsers().stream();
//limit skip distinct 用法差不多
stream.filter(user -> user.getSalary()>10000).forEach(System.out::println);
}
#映射
@Test
public void test6(){
// map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,
// 该函数会被应用到每个元素上,并将其映射成一个新的元素。
List<String> list = Arrays.asList("aaa", "bb", "cccc", "dd");
//消费型接口
list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
//匹配名字长度大于2的人员
list.stream().map(user::getName).filter(name->name.length()>2).forEach(System.out::println);
// flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
// 类似于list的addAll方法 将多维嵌套的数据转换成单维数据
Stream<Character> characterStream = list.stream().flatMap(streamTest::fromStringToStream);
characterStream.forEach(System.out::println); //获取每个集合中每个字符串的每个字符
}
//将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for(Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
#排序
@Test
public void test7(){
// sorted()——自然排序
List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);
list.stream().sorted().forEach(System.out::println);
//sorted(Comparator com) -- 定制排序
List<user> users = streamTest.getUsers();
users.stream().sorted( (e1,e2) -> {
int ageValue = Double.compare(e1.getAge(),e2.getAge());
if(ageValue != 0){
return ageValue;
}else{
//年纪相等再比较工资
return -Double.compare(e1.getSalary(),e2.getSalary()); //从大到小排序
}
}).forEach(System.out::println);
}
终止操作
终端操作会从流的流水线生成结果。流进行了终止操作后,不能再次使用。
//1-匹配与查找
@Test
public void test11(){
List<user> users = streamTest.getUsers();
// allMatch(Predicate p)——检查是否匹配所有元素。
boolean allMatch = users.stream().allMatch(e -> e.getAge() > 18);
System.out.println(allMatch);
// findFirst——返回第一个元素
Optional<user> user = users.stream().findFirst();
System.out.println(user);
}
@Test
public void test12(){
List<user> users = streamTest.getUsers();
// count——返回流中元素的总个数
long count = users.stream().filter(e -> e.getSalary() > 5000).count();
System.out.println(count);
// max(Comparator c)——返回流中最大值
Stream<Double> salaryStream = users.stream().map(e -> e.getSalary());
Optional<Double> maxSalary = salaryStream.max(Double::compare);
System.out.println(maxSalary);
// forEach(Consumer c)——内部迭代
users.stream().forEach(System.out::println);
//使用集合的遍历操作
users.forEach(System.out::println);
}
//2-归约
@Test
public void test13(){
// reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
// 计算1-10的自然数的和
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0, Integer::sum);
System.out.println(sum);
// reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
// 计算所有员工工资的总和
List<user> users = streamTest.getUsers();
Stream<Double> salaryStream = users.stream().map(user::getSalary);
// Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
Optional<Double> sumMoney = salaryStream.reduce((d1, d2) -> d1 + d2);
System.out.println(sumMoney.get());
}
//3-收集
@Test
public void test14(){
//collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
//查找工资大于6000的员工,结果返回为一个List或Set
List<user> users = streamTest.getUsers();
List<user> userList =users.stream()
.filter(e -> e.getSalary()>6000).collect(Collectors.toList());
userList.forEach(System.out::println);
Set<user> userSet = users.stream()
.filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
userSet.forEach(System.out::println);
}
//连接流中每个字符串
list.stream().collect(Collectors.joining()); 等价 String.join("", list)
Optional类
是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。
创建Optional类对象的方法:
- Optional.of(T t) :创建一一个 Optional实例,t必须非空;
- Optional.empty() :创建一个空 的Optional 实例
- Optional.ofNullable(T t): t可以为null
判断Optional容器中是否包含对象:
boolean isPresent() :判断是否包含对象
void ifPresent(Consumer<? super T> consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
获取Optional容器的对象:
- T get():如果调用对象包含值,返回该值,否则抛异常
- T orElse(T other): 如果有值则将其返回,否则返回指定的other对象。
- T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
- T orElse Throw(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
#举例 保证当user为空时不影响下面逻辑代码的执行
User user = null;
User optUser = Optional.ofNullable(user).orElse(new User("a",12));
System.out.println(optUser.getName());