发布于2021-05-29 19:06 阅读(1254) 评论(0) 点赞(22) 收藏(1)
接口提供 default 关键字实现默认方法,可以直接使用,不用强制实现默认方法。
Java 8 允许我们通过 default
关键字对接口中定义的抽象方法提供一个默认的实现。
请看下面示例代码:
// 定义一个公式接口
interface Formula {
// 计算
double calculate(int a);
// 求平方根
default double sqrt(int a) {
return Math.sqrt(a);
}
}
在上面这个接口中,我们除了定义了一个抽象方法 calculate
,还定义了一个带有默认实现的方法 sqrt
。 我们在实现这个接口时,可以只需要实现 calculate
方法,默认方法 sqrt
可以直接调用即可,也就是说我们可以不必强制实现 sqrt
方法。
补充:通过
default
关键字这个新特性,可以非常方便地对之前的接口做拓展,而此接口的实现类不必做任何改动。
Formula formula = new Formula() {
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
formula.calculate(100); // 100.0
formula.sqrt(16); // 4.0
上面通过匿名对象实现了 Formula
接口。但是即使是这样,我们为了完成一个 sqrt(a * 100)
简单计算,就写了 6 行代码,很是冗余。
Lambda表达式由用逗号分隔的参数列表、–>符号、函数体三部分表示 e -> System.out.println( e ) 举几个例子
在学习 Lambda
表达式之前,我们先来看一段老版本的示例代码,其对一个含有字符串的集合进行排序:
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
Collections
工具类提供了静态方法 sort
方法,入参是一个 List
集合,和一个 Comparator
比较器,以便对给定的 List
集合进行 排序。上面的示例代码创建了一个匿名内部类作为入参,这种类似的操作在我们日常的工作中随处可见。
Java 8 中不再推荐这种写法,而是推荐使用 Lambda 表达:
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
正如你看到的,上面这段代码变得简短很多而且易于阅读。但是我们还可以再精炼一点:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
对于只包含一行方法的代码块,我们可以省略大括号,直接 return
关键代码即可。追求极致,我们还可以让它再短点:
names.sort((a, b) -> b.compareTo(a));
**说明:**并不是所有接口抽象方法都可以改写为lambda 表达式,只能是函数式接口,就是一个接口只有一个抽象方法,可以default 声明默认方法。
类的引用,class::new 构造器
class:: static_method 静态方法
class::methon 方法
instance::methon 对象对方法的引用
**说明: 访问成员变量值不能更改,更改后访问不了,可以不声明fanal **
在 Lambda 表达式中,我们可以访问外部的 final
类型变量,如下面的示例代码:
// 转换器
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
final int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3
与匿名内部类不同的是,我们不必显式声明 num
变量为 final
类型,下面这段代码同样有效:
int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3
但是 num
变量必须为隐式的 final
类型,何为隐式的 final
呢?就是说到编译期为止,num
对象是不能被改变的,如下面这段代码,就不能被编译通过:
int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
num = 3;
在 lambda 表达式内部改变 num
值同样编译不通过,需要注意, 比如下面的示例代码:
int num = 1;
Converter<Integer, String> converter = (from) -> {
String value = String.valueOf(from + num);
num = 3;
return value;
};
当时,我们在接口中定义了一个带有默认实现的 sqrt
求平方根方法,在匿名内部类中我们可以很方便的访问此方法:
Formula formula = new Formula() {
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
但是在 lambda 表达式中可不行:
Formula formula = (a) -> sqrt(a * 100);
带有默认实现的接口方法,是不能在 lambda 表达式中访问的,上面这段代码将无法被编译通过。
List<String> myList =
Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList
.stream() // 创建流
.filter(s -> s.startsWith("c")) // 执行过滤,过滤出以 c 为前缀的字符串
.map(String::toUpperCase) // 转换成大写
.sorted() // 排序
.forEach(System.out::println); // for 循环打印
// C1
// C2
复制代码
我们可以对流进行中间操作或者终端操作。小伙伴们可能会疑问?什么是中间操作?什么又是终端操作?
Stream中间操作,终端操作
filter
过滤,map
对象转换,sorted
排序,就属于中间操作。void
或者一个非流的结果。上图中的 forEach
循环 就是一个终止操作。看完上面的操作,感觉是不是很像一个流水线式操作呢。
实际上,大部分流操作都支持 lambda 表达式作为参数,正确理解,应该说是接受一个函数式接口的实现作为参数。
任何数据源都可以使用stream 来表示,最为常见的为 conlection 集合,list,set 使用 list.stream()方法创建流
也可以直接使用 stream.of() 方法进行创建流
Stream.of("a1", "a2", "a3")
.findFirst()
.ifPresent(System.out::println); // a1
除了常规对象流之外,Java 8还附带了一些特殊类型的流,用于处理原始数据类型int
,long
以及double
。说道这里,你可能已经猜到了它们就是IntStream
,LongStream
还有DoubleStream
。
IntStream.range(1, 4)
.forEach(System.out::println); // 相当于 for (int i = 1; i < 4; i++) {} //intStream.range()可以用来代替常规的for循环
// 1
// 2
// 3
IntFunction
代替Function
,IntPredicate
代替Predicate
。sum()
以及average()
,如下所示:两种对象流进行互转操作
常规对象流转换为 原始对象流:mapToInt (),mapToLong() ,mapToDouble()
原始对象流转换为常规对象流 :mapToObj()
Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> {
System.out.println("filter: " + s);
return true;
});
不会打印任何东西,原因是需要有终端操作才会执行中间操作
Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> {
System.out.println("filter: " + s);
return true;
})
.forEach(s -> System.out.println("forEach: " + s));
复制代码
再次执行,我们会看到输出如下:
filter: d2
forEach: d2
filter: a2
forEach: a2
filter: b1
forEach: b1
filter: b3
forEach: b3
filter: c
forEach: c
疑问为什么不是先执行完 filter 再执行 foreach操作的,处于性能的考虑,是垂直执行的。
当一个流使用终端操作时,流会关闭,可以使用 Supplier 来包装流得到一个新的流
为了克服这个限制,我们必须为我们想要执行的每个终端操作创建一个新的流链,例如,我们可以通过 Supplier
来包装一下流,通过 get()
方法来构建一个新的 Stream
流,如下所示:
Supplier<Stream<String>> streamSupplier =
() -> Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> s.startsWith("a"));
streamSupplier.get().anyMatch(s -> true); // ok
streamSupplier.get().noneMatch(s -> true); // ok
Collect 可以将流中的元素转换为不同的对象,例如 list,set,map ,collect 接受一个 Collector 搜集器
List<Person> filtered =
persons
.stream() // 构建流
.filter(p -> p.name.startsWith("P")) // 过滤出名字以 P 开头的
.collect(Collectors.toList()); // 生成一个新的 List 转换为set为Collectors.toSet()
System.out.println(filtered); // [Peter, Pamela]
**作用:**可以将每个对象流转换为 0 个,一个,多个对象流
class Foo {
String name;
List<Bar> bars = new ArrayList<>();
Foo(String name) {
this.name = name;
}
}
class Bar {
String name;
Bar(String name) {
this.name = name;
}
}
复制代码
接下来,通过我们上面学习到的流知识,来实例化一些对象:
List<Foo> foos = new ArrayList<>();
// 创建 foos 集合
IntStream
.range(1, 4)
.forEach(i -> foos.add(new Foo("Foo" + i)));
// 创建 bars 集合
foos.forEach(f ->
IntStream
.range(1, 4)
.forEach(i -> f.bars.add(new Bar("Bar" + i + " <- " + f.name))));
复制代码
我们创建了包含三个foo
的集合,每个foo
中又包含三个 bar
。
flatMap
的入参接受一个返回对象流的函数。为了处理每个foo
中的bar
,我们需要传入相应 stream 流:
foos.stream()
.flatMap(f -> f.bars.stream())
.forEach(b -> System.out.println(b.name));
// Bar1 <- Foo1
// Bar2 <- Foo1
// Bar3 <- Foo1
// Bar1 <- Foo2
// Bar2 <- Foo2
// Bar3 <- Foo2
// Bar1 <- Foo3
// Bar2 <- Foo3
// Bar3 <- Foo3
复制代码
如上所示,我们已成功将三个 foo
对象的流转换为九个bar
对象的流。
//中间操作符
/**
* filter:过滤出想要的元素
*/
@Test
public void filter(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac");
List<String> filter = list.stream().filter(s -> s.contains("a")).collect(Collectors.toList());
System.out.println(filter);
}
/**
* distinct:去除集合中相同的元素
*/
@Test
public void distinct(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
List<String> distincted = list.stream().distinct().collect(Collectors.toList());
System.out.println(distincted);
List<User> users = new ArrayList<>();
users.add(new User(1, "zs"));
users.add(new User(1, "zs"));
users.add(new User(2, "yijian"));
List<User> userList = users.stream().distinct().collect(Collectors.toList());
System.out.println(userList);
}
/**
* limit:获取流中的前几个元素
*/
@Test
public void limit(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
List<String> limit = list.stream().limit(3).collect(Collectors.toList());
System.out.println(limit);
}
/**
* skip:获取流中的后几个元素
*/
@Test
public void skip(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
List<String> sikp = list.stream().skip(3).collect(Collectors.toList());
System.out.println(sikp);
}
/**
* map:对流中的元素做统一的处理
*/
@Test
public void map(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
List<String> map = list.stream().map(s -> "map"+s).collect(Collectors.toList());
System.out.println(map);
List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,1);
List<Integer> integers = integerList.stream().map(integer -> integer + 1).collect(Collectors.toList());
System.out.println(integers);
}
/**
* sort:对集合中的元素进行排序
*/
@Test
public void sort(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
List<String> collect = list.stream().sorted().collect(Collectors.toList());
System.out.println(collect);
List<Integer> list1 = Arrays.asList(30,1,-1,3,7);
List<Integer> collect1 = list1.stream().sorted((o1, o2) -> o2-o1).collect(Collectors.toList());
System.out.println(collect1);
}
// 终止操作符
/**
* anyMatch: 判断集合中是否有一个元素满足条件
*/
@Test
public void anyMatch(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
boolean match = list.stream().anyMatch(s -> s.contains("yijian"));
System.out.println(match);
}
/**
* allMatch: 判断集合中是否所有元素都满足条件
*/
@Test
public void allMatch(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
boolean match = list.stream().allMatch(s -> s.contains("yijian"));
System.out.println(match);
}
/**
* noneMatch: 判断集合中是否所有元素都不满足条件
*/
@Test
public void noneMatch(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
boolean match = list.stream().noneMatch(s -> s.contains("yijian"));
System.out.println(match);
}
/**
* findAny: 从集合中随机返回一个元素
*/
@Test
public void findAny(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
// 因为Stream 是串行的,默认返回第一个元素,提高效率
// 可以改为parallelStream 让他并行执行
Optional<String> any = list.parallelStream().findAny();
if (any.isPresent()){
System.out.println(any.get());
}
}
/**
* findFirst: 从集合中随机返回第一个元素
*/
@Test
public void findFirst(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
// 因为Stream 是串行的,默认返回第一个元素,提高效率
// 可以改为parallelStream 让他并行执行
Optional<String> any = list.parallelStream().findFirst();
if (any.isPresent()){
System.out.println(any.get());
}
}
/**
* collect:将流转换为其他形式:list、set、map
*/
@Test
public void collect(){
List<String> list = Arrays.asList("qw", "yijian", "ad", "efg","ac","yijian");
Set<String> collect = list.stream().collect(Collectors.toSet());
System.out.println(collect);
// Collectors.toMap(key -> key, value -> value, (oldKey, newKey) -> newKey)
Map<String, String> collect1 = list.stream().collect(Collectors.toMap(key -> key, value -> value, (oldKey, newKey) -> newKey));
System.out.println(collect1);
}
/**
* reduce:将流中的元素结合起来
*/
@Test
public void reduce(){
List<Integer>list = Arrays.asList(1,2,3,5,6,6,2,1);
// reduce((初始值,每一项的值))
Optional<Integer> optional = list.stream().reduce((initialValue, itemValue) -> {
return initialValue + itemValue;
});
if (optional.isPresent()){
System.out.println(optional.get());
}
// reduce(初始值,(初始值,每一项的值))
Integer integer = list.stream().reduce(1, (initialValue, itemValue) -> {
return initialValue + itemValue;
});
System.out.println(integer);
}
/**
* count:获取集合中元素数量
*/
@Test
public void count(){
List<Integer>list = Arrays.asList(1,2,3,5,6,6,2,1);
Optional<Integer> max = list.stream().max((o1, o2) -> {
return o1 - o2;
});
System.out.println(max);
System.out.println("集合中元素的个数:"+list.stream().count());
}
}
作者:skdk
链接:http://www.javaheidong.com/blog/article/207116/1b00b70c7c311eeee21a/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!