赞
踩
Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Java 8 是oracle公司于2014年3月发布,可以看成是自Java 5 以 来最具革命性的版本。Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性。
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
我们看如下代码就可用lamdba表达式进行简化
Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:左侧:指定了 Lambda 表达式需要的参数列表 右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即Lambda 表达式要执行的功能。
lamdba表达式只能针对函数式接口进行操作,进行简化。只包含一个抽象方法的接口,称为函数式接口
类型推断
上述 Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”。
public class LamdbaDemo1 { @Test public void test1() { //1.语法格式一 函数式接口的抽象方法没有参数列表没有返回值 Runnable runnable = new Runnable() { @Override public void run() { System.out.println("正常写法"); } }; runnable.run(); System.out.println("------------------"); //2.lambda表达式写法 Runnable runnable2 = () -> {System.out.println("lambda表达式写法");}; runnable2.run(); } @Test public void test2() { //1.语法格式二 函数式接口的抽象方法 有一个参数,但没有返回值 Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String t) { System.out.println(t); } }; consumer.accept("我爱你中国"); System.out.println("------------"); //2.lamdba表达式写法 Consumer<String> consumer2 = (String t) ->{System.out.println(t);}; consumer2.accept("我爱你中国"); } @Test public void test3() { //1.语法格式三 函数式接口的抽象方法 有一个参数,但没有返回值 Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String t) { System.out.println(t); } }; consumer.accept("我爱你中国"); System.out.println("------------"); //2.类型推断 不用指定String类型 Consumer<String> consumer2 = (t) ->{System.out.println(t);}; consumer2.accept("我爱你中国"); } @Test public void test4() { //1.语法格式四 函数式接口的抽象方法 有一个参数,但没有返回值 Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String t) { System.out.println(t); } }; consumer.accept("我爱你中国"); System.out.println("------------"); //2.在三的基础上省略小() Consumer<String> consumer2 = t ->{System.out.println(t);}; consumer2.accept("我爱你中国"); } @Test public void test5() { //1.语法格式5 函数式接口的抽象方法 有多个参数列表多条执行语句并有返回值 Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); } }; System.out.println(comparator.compare(1, 2)); System.out.println("----------"); //2.lambda简写 Comparator<Integer> comparator2 = (o1,o2)->{ System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); }; System.out.println(comparator2.compare(1, 2)); } @Test public void test6() { //1.语法格式6:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略 Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }; System.out.println(comparator.compare(1, 2)); System.out.println("------------"); Comparator<Integer> comparator2 = (o1,o2)->o1.compareTo(o2); System.out.println(comparator2.compare(1, 2)); } }
例如:Comparator就是一个函数式接口
当然我们也可以自定义函数式接口,如下所示:
当函数式接口的抽象方法的参数列表以及返回值和实现方法的调用者一致时,可以采用对象::实例方法名
进行 方法引用
@Test//1.情况1:对象实例方法 public void test1() { //1.函数式接口正常创建匿名对象 Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String t) { System.out.println(t); } }; //2.lambda表达式的方式创建匿名对象 Consumer<String> consumer2 = (t) -> System.out.println(t); //3.方法引用的方式 /** * 可以这么调用的原因 * 1.接口中的抽象方法accept的参数列表和println()方法参数列表相同返回值也相同 * */ Consumer<String> consumer3 = System.out::println; } @Test//1.情况1:对象实例方法 public void test2() { User user = new User(1, "小黑", "123456"); //1.正常表示 Supplier<String> supplier = new Supplier<String>() { @Override public String get() { return user.getName(); } }; //2.lambda表达式 Supplier<String> supplier2 = ()->user.getName(); /** * user.getName() 方法返回值String和抽象方法get() 返回值一样,参数列表一样 */ //3.方法的引用方式 Supplier<String> supplier3 = user::getName; }
@Test//情况2 类名::静态方法名 public void test3() { //1.正常表示 Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); } }; //2.lambda表示方式 Comparator<Integer> comparator2 = (o1,o2)-> Integer.compare(o1, o2); //3.静态方法引用表示 Comparator<Integer> comparator3 = Integer :: compare; System.out.println(comparator3.compare(3, 4)); } @Test//情况2 类名::静态方法名 public void test4() { //1.正常写法 Function<Double, Long> function = new Function<Double, Long>() { @Override public Long apply(Double t) { return Math.round(t); } }; //2.lambda表达式写法 Function<Double, Long> function2 = (t)->Math.round(t); //3.方法引用表示 /** * 可以这么表示的原因:Math.round() 和appli() 方法参数列表相同,返回值相同 */ Function<Double, Long> function3 = Math::round; }
@Test//情况3 类名::实例方法 public void test5() { //1.正常写法 Comparator<String> comm1 = new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } }; //2.lambda表达式写法 Comparator<String> comm2 = (o1,o2)->o1.compareTo(o2); //3.方法引用表示 Comparator<String> comm3 = String::compareTo; System.out.println(comm3.compare("a", "b")); } @Test//情况3 类名::实例方法 public void test6() { //1.正常写法 BiPredicate<String,String> biPredicate = new BiPredicate<String, String>(){ @Override public boolean test(String t, String u) { return t.equals(u); } }; //2.lambda表达式写法 BiPredicate<String, String> biPredicate2 = (str1,str2)->str1.equals(str2); //3.方法引用 BiPredicate<String, String> biPredicate3 = String::equals; System.out.println(biPredicate3.test("abc", "abc")); }
格式: **ClassName::new **
与函数式接口相结合,自动与函数式接口中方法兼容。 可以把构造器引用赋值给定义的方法,要求构造器参数列表要与接口中抽象 方法的参数列表一致!且方法的返回值即为构造器对应类的对象。
案例
@Test
public void test1() {
//1.正常写法
Supplier<User> supplier = new Supplier<User>() {
@Override
public User get() {
return new User();
}
};
//2.lambda写法
Supplier<User> supplier2 = ()->new User();
//3.构造方法引用
Supplier<User> supplier3 = User::new;
}
格式: type[] :: new
案例
@Test
public void test2() {
//1.正常写法
Function<Integer, User[]> function = new Function<Integer, User[]>() {
@Override
public User[] apply(Integer t) {
return new User[t];
}
};
//2.lambda表达式写法
Function<Integer, User[]> function2 = (length)->new User[length];
//3.数组引用
Function<Integer, User[]> function3 = User[]::new;
}
Stream到底是什么呢
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,Stream讲的是计算!”
注意
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
@Test
public void test1() {
Collection c1 = new ArrayList();
//1.返回一个顺序流
Stream stream = c1.stream();
//2.返回一个并行流
Stream parallelStream = c1.parallelStream();
}
Java8
中的 Arrays 的静态方法 stream() 可以获取数组流:
IntStream
stream(int[] array)LongStream
stream(long[] array)DoubleStream
stream(double[] array)@Test//2.通过数组工具类创建stream流
public void tes2() {
//1.创建数组
int[] arr = {1,2,3};
long[] arr2 = {1L,2L,3L};
double[] arr3 = {1.1,2.2,3.3};
//2.通过数组工具类创建stream流
IntStream stream = Arrays.stream(arr);
LongStream stream2 = Arrays.stream(arr2);
DoubleStream stream3 = Arrays.stream(arr3);
User[] users = {new User(1, "瑶", 8000.2),new User(2, "明世隐", 9000.2)};
Stream<User> stream4 = Arrays.stream(users);
}
可以调用Stream类静态方法 of(), 通过显示值创建一个流。它可以接收任意数量的参数。
@Test
public void test3() {
Stream<Integer> stream = Stream.of(1,2,3);
}
可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。
@Test//1.创建无限流
public void test4() {
//1.创建无线流 初始值是0 然后流中的数据加1.
Stream<Integer> stream = Stream.iterate(0, t->t+1);
stream.limit(10).forEach(System.out::println);
//2.生成
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
方法 | 描述 |
---|---|
filter(Predicate p) | 接收 Lambda , 从流中排除某些元素 |
distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回空 |
@Test//1.帅选与切片
public void test1() {
//1.接收 Lambda , 从流中排除某些元素
List<User> data = UserList.getData();
//1.判断工资大于9000的用户
data.stream().filter(user->user.getMoney()>9000).forEach(System.out::println);
System.out.println("***************************");
//2.截取前三条数据
data.stream().limit(3).forEach(System.out::println);
//3.跳过前三条记录
data.stream().skip(3).forEach(System.out::println);
//4.去重复数据 // 要重写hashCode 和equals方法
data.stream().distinct().forEach(System.out::println);
}
方法 | 描述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 ` 素上,产生一个新的 LongStream。 |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
@Test//2.映射 public void test2() { //1.映射 将小写字母映射成大小字母 List<String> list = Arrays.asList("aa","bb","cc","dd"); list.stream().map(t->t.toUpperCase()).forEach(System.out::println); list.stream().map(String::toUpperCase).forEach(System.out::println); //2.映射用户姓名等于1的姓名 List<User> data = UserList.getData(); Stream<User> filter = data.stream().filter(user->user.getName().length()==1); filter.map(User::getName).forEach(System.out::println); System.out.println("-----------"); //3.flatMap(Function f)——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。 List<String> list2 = Arrays.asList("aaa","bbb","ccc","ddd"); list2.stream().flatMap(str->StreamDemo1.getStream(str)).forEach(System.out::println); } public static Stream<Character> getStream(String str) { ArrayList<Character> list = new ArrayList<>(); for(Character c : str.toCharArray()){ list.add(c); } return list.stream(); }
方法名 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator com) | 产生一个新流,其中按比较器顺序排序 |
@Test//2.排序
public void test3() {
//1.自然排序
List<Integer> list = Arrays.asList(1,2,3,9,-1,0);
list.stream().sorted().forEach(System.out::println);
//2.定制排序
List<User> listUser = UserList.getData();
listUser.stream().sorted((u1,u2)->{
return Double.compare(u1.getMoney(), u2.getMoney());
}).forEach(System.out::println);
}
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
**注意:**流进行了终止操作后,不能再次使用
方法 | 描述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了) |
@Test
public void test1() {
//1.查看所有有用户的钱都大于5000
List<User> list = UserList.getData();
boolean tag = list.stream().allMatch(u->u.getMoney()>5000);
System.out.println(tag);
//2.至少一个一个用户的前大于9000的
System.out.println(list.stream().anyMatch(u->u.getMoney()>9000));
//3.查看是否没有叫蔡文姬的用户
System.out.println(list.stream().noneMatch(u->u.getName().equals("蔡文姬")));
//4.返回第一个元素
Optional<User> findFirst = list.stream().findFirst();
System.out.println(findFirst.get());
}
@Test
public void test2() {
List<User> list = UserList.getData();
//1.返回流中总个数
long count = list.stream().count();
System.out.println(count);
//2.返回流中最大值
List<Double> list2 = Arrays.asList(12.2,3.3,99.9);
Optional<Double> max = list2.stream().max((o1,o2)->Double.compare(o1, o2));
System.out.println(max.get());
//3.内部迭代
list2.stream().forEach(System.out::println);
//4.外部集合直接迭代
list2.forEach(System.out::println);
}
方法 | 描述 |
---|---|
reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 Optional |
@Test//规约
public void test3() {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
//1.计算元素的累加和初始值是0
Integer reduce = list.stream().reduce(0, Integer::sum);
System.out.println(reduce);
Optional<Integer> reduce2 = list.stream().reduce(Integer::sum);
System.out.println(reduce2.get());
}
Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、Map)。
@Test//收集
public void test4() {
Set<User> set = UserList.getData().stream().filter(u->u.getMoney()>9000).collect(Collectors.toSet());
set.forEach(System.out::println);
}
到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。 以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类, Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代 码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。
Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不 存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在 则isPresent()方法会返回true,调用get()方法会返回该对象。
@Test
public void test1() {
User user = new User(1,"小黑",99.99);
user = null;
Optional<User> optional = Optional.ofNullable(user);
User u = optional.orElse(new User(0,"默认",0.0));
System.out.println(u);
}
er T> consumer) :如果有值,就执行Consumer 接口的实现代码,并且该值会作为参数传给它。
@Test
public void test1() {
User user = new User(1,"小黑",99.99);
user = null;
Optional<User> optional = Optional.ofNullable(user);
User u = optional.orElse(new User(0,"默认",0.0));
System.out.println(u);
}
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。