当我们在需要对集合中的元素进行操作的时候,除了必需的添加,删除,获取外,最典型的操作就是集合遍历,看一段代码
public static void main(String[] args) {
// 定义一个List集合
List<String> list = Arrays.asList("张三", "张三丰", "成龙", "周星驰");
// 1.获取所有 姓张的信息
List<String> list1 = new ArrayList<>();
for (String s : list) {
if (s.startsWith("张")) {
list1.add(s);
}
}
// 2.获取名称长度为3的用户
List<String> list2 = new ArrayList<>();
for (String s : list1) {
if (s.length() == 3) {
list2.add(s);
}
}
// 3. 输出所有的用户信息
for (String s : list2) {
System.out.println(s);
}
}
上面的代码针对与我们不同的需求总是一次次的循环循环循环.这时我们希望有更加高效的处理方式,这时我们就可以通过
JDK8
中提供的Stream API
来解决这个问题了。
public static void main(String[] args) {
// 定义一个List集合
List<String> list = Arrays.asList("张三", "张三丰", "成龙", "周星驰");
list.stream()
// 1.获取所有 姓张的信息
.filter(s -> s.startsWith("张"))
// 2.获取名称长度为3的用户
.filter(s -> s.length() == 3)
// 3. 输出所有的用户信息
.forEach(System.out::println);
}
Stream
和IO
流(InputStream/OutputStream
)没有任何关系,请暂时忘记对传统IO
流的固有印象
Stream
流式思想类似于工厂车间的“生产流水线”,Stream
流不是一种数据结构,不保存数据,而是对数据进行加工 处理。Stream
可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
Stream API
能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。
java.util.Collection
接口中加入了default
方法stream
,也就是说Collection
接口下的所有的实 现都可以通过stream
方法来获取Stream
流。
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.stream();
Set<String> set = new HashSet<>();
set.stream();
Vector vector = new Vector();
vector.stream();
}
由于
Map
接口别没有实现Collection
接口,可以根据Map
获取对应的key
value
的集合。
public static void main(String[] args) {
Map<String,Object> map = new HashMap<>();
Stream<String> stream = map.keySet().stream(); // key
Stream<Object> stream1 = map.values().stream(); // value
Stream<Map.Entry<String, Object>> stream2 = map.entrySet().stream(); //entry
}
在实际开发中我们不可避免的还是会操作到数组中的数据,由于数组对象不可能添加默认方法,所有
Stream
接口中提供了静态方法of
,基本数据类型的数组是不行的
public static void main(String[] args) {
Stream<String> a1 = Stream.of("a1", "a2", "a3");
String[] arr1 = {"aa","bb","cc"};
Stream<String> arr11 = Stream.of(arr1);
Integer[] arr2 = {1,2,3,4};
Stream<Integer> arr21 = Stream.of(arr2);
arr21.forEach(System.out::println);
}
方法名 | 方法作用 | 返回值类型 | 方法种类 |
---|---|---|---|
count | 统计个数 | long | 终结 |
forEach | 逐一处理 | void | 终结 |
filter | 过滤 | Stream | 函数拼接 |
limit | 取用前几个 | Stream | 函数拼接 |
skip | 跳过前几个 | Stream | 函数拼接 |
map | 映射 | Stream | 函数拼接 |
concat | 组合 | Stream | 函数拼接 |
终结方法:返回值类型不再是
Stream
类型的方法,不再支持链式调用。本小节中,终结方法包括count
和forEach
方法。
非终结方法:返回值类型仍然是
Stream
类型的方法,支持链式调用。(除了终结方法外,其余方法均为非终结方法。)
注意事项
Stream
只能操作一次Stream
方法返回的是新的流Stream
不调用终结方法,中间的操作不会执行
forEach
用来遍历流中的数据的
public static void main(String[] args) {
Stream.of("1", "2", "3").forEach(System.out::println);
}
该方法接受一个
Consumer
接口(一个输入,没有返回),会将每一个流元素交给函数处理
void forEach(Consumer<? super T> action)
Stream
流中的count
方法用来统计其中的元素个数的
public static void main(String[] args) {
System.out.println(Stream.of("1", "2", "3").count());
}
该方法返回一个long值,代表元素的个数
long count();
filter
方法的作用是用来过滤数据的,返回符合条件的数据,也可以通过filter
方法将一个流转换成另一个子集流
public static void main(String[] args) {
Stream.of("a1", "a2", "a3", "bb", "cc", "aa", "dd")
.filter((s) -> s.contains("a"))
.forEach(System.out::println);
}
该接口接收一个
Predicate
函数式接口(一个输入,返回boolean
)参数作为过滤条件
Stream<T> filter(Predicate<? super T> predicate);
limit
方法可以对流进行截取处理,只取前n
个数据
public static void main(String[] args) {
Stream.of("a1", "a2", "a3", "bb", "cc", "aa", "dd")
.limit(3)
.forEach(System.out::println);
}
参数是一个
long
类型的数值,如果集合当前长度大于参数就进行截取,否则不操作
如果希望跳过前面几个元素,可以使用
skip
方法获取一个截取之后的新流
public static void main(String[] args) {
Stream.of("a1", "a2", "a3", "bb", "cc", "aa", "dd")
.skip(3)
.forEach(System.out::println);
}
如果我们需要将流中的元素映射到另一个流中,可以使用
map
方法
public static void main(String[] args) {
Stream.of("1", "2", "3", "4", "5", "6", "7")
.map(Integer::parseInt)
.forEach(System.out::println);
}
该接口需要一个
Function
函数式接口参数,可以将当前流中的T
类型数据转换为另一种R
类型的数据
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
如果需要将数据排序,可以使用
sorted
方法
public static void main(String[] args) {
Stream.of("1", "3", "2", "4", "0", "9", "7")
.map(Integer::parseInt)
// 根据数据的自然顺序排序
//.sorted()
// 根据比较强指定排序规则
.sorted((o1, o2) -> o2 - o1)
.forEach(System.out::println);
}
如果要去掉重复数据,可以使用
distinct
方法
public static void main(String[] args) {
Stream.of(
new Person("张三", 18)
, new Person("李四", 22)
, new Person("张三", 18)
).distinct()
.forEach(System.out::println);
}
Stream
流中的distinct
方法对于基本数据类型是可以直接出重的,但是对于自定义类型,我们是需要重写hashCode
和equals
方法来移除重复元素。
如果需要判断数据是否匹配指定的条件,可以使用
match
相关的方法
public static void main(String[] args) {
boolean b = Stream.of("1", "3", "3", "4", "5", "1", "7")
.map(Integer::parseInt)
// 元素是否都满足条件
//.allMatch(s -> s > 0)
// 元素是否有任意一个满足条件
//.anyMatch(s -> s >4)
// 元素是否都不满足条件
.noneMatch(s -> s > 4);
System.out.println(b);
}
如果需要将所有数据归纳得到一个数据,可以使用
reduce
方法
public static void main(String[] args) {
Integer sum = Stream.of(4, 5, 3, 9)
// 第一个参数identity是默认值,第一次的时候会将默认值赋值给x,之后每次会将上一次的操作结果赋值给x y就是每次从数据中获取的元素
.reduce(0, (x, y) -> {
System.out.println("x=" + x + ",y=" + y);
return x + y;
});
System.out.println(sum);
// 获取 最大值
Integer max = Stream.of(4, 5, 3, 9)
.reduce(0, (x, y) -> x > y ? x : y);
System.out.println(max);
}
如果有两个流,希望合并成为一个流,那么可以使用
Stream
接口的静态方法concat
public static void main(String[] args) {
Stream<String> stream1 = Stream.of("a", "b", "c");
Stream<String> stream2 = Stream.of("x", "y", "z");
// 通过concat方法将两个流合并为一个新的流
Stream.concat(stream1, stream2).forEach(System.out::println);
}
如果我们需要找到某些数据,可以使用
find
方法来实现 ,返回的Optional
对象,关于这个对象,后面会提到
Optional<T> findFirst();
Optional<T> findAny();
通过名字,就可以看到,对这个集合的流,做一系列的中间操作后,可以调用
findFirst
,返回集合的第一个对象,findAny
返回这个集合中,取到的任何一个对象
findAny
和findFirst
返回的,都是第一个对象findAny
返回的是最快处理完的那个线程的数据,所以说,在并行操作中,对数据没有顺序上的要求,那么findAny
的效率会比findFirst
要快的public static void main(String[] args) {
Optional<String> first = Stream.of("1", "3", "3", "4", "5", "1",
"7").findFirst();
System.out.println(first.get());
Optional<String> any = Stream.of("1", "3", "3", "4", "5", "1",
"7").findAny();
System.out.println(any.get());
}
如果我们想要获取最大值和最小值,那么可以使用
max
和min
方法,返回的对象同样是Optional
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
使用
public static void main(String[] args) {
Optional<Integer> max = Stream.of("1", "3", "3", "4", "5", "1", "7")
.map(Integer::parseInt)
.max(Comparator.comparingInt(o -> o));
System.out.println(max.get());
Optional<Integer> min = Stream.of("1", "3", "3", "4", "5", "1", "7")
.map(Integer::parseInt)
.min(Comparator.comparingInt(o -> o));
System.out.println(min.get());
}
如果需要将
Stream
中的Integer
类型转换成int
类型,可以使用mapToInt
方法来实现
public static void main(String[] args) {
// Integer占用的内存比int多很多,在Stream流操作中会自动装修和拆箱操作
Integer[] arr = {1, 2, 3, 5, 6, 8};
Stream.of(arr)
.filter(i -> i > 0)
.forEach(System.out::println);
System.out.println("---------");
// 为了提高程序代码的效率,我们可以先将流中Integer数据转换为int数据,然后再操作
IntStream intStream = Stream.of(arr)
.mapToInt(Integer::intValue);
intStream.filter(i -> i > 3)
.forEach(System.out::println);
}
在实际开发中我们经常会将
map
和reduce
一块来使用
public static void main(String[] args) {
// 1.求出所有年龄的总和
Integer sumAge = Stream.of(new Person("张三", 18)
, new Person("李四", 22)
, new Person("张三", 13)
, new Person("王五", 15)
, new Person("张三", 19))
// 实现数据类型的转换
.map(Person::getAge)
.reduce(0, Integer::sum);
System.out.println(sumAge);
// 2.求出所有年龄中的最大值
Integer maxAge = Stream.of(new Person("张三", 18)
, new Person("李四", 22)
, new Person("张三", 13)
, new Person("王五", 15)
, new Person("张三", 19))
// 实现数据类型的转换,符合reduce对数据的要求
.map(Person::getAge)
// reduce实现数据的处理
.reduce(0, Math::max);
System.out.println(maxAge);
// 3.统计 字符 a 出现的次数
Integer count = Stream.of("a", "b", "c", "d", "a", "c", "a")
.map(ch -> "a".equals(ch) ? 1 : 0)
.reduce(0, Integer::sum);
System.out.println(count);
}
定义两个集合,然后在集合中存储多个用户名称。然后完成如下的操作:
Person
对象Person
信息/**
* 1. 第一个队伍只保留姓名长度为3的成员
* 2. 第一个队伍筛选之后只要前3个人
* 3. 第二个队伍只要姓张的成员
* 4. 第二个队伍筛选之后不要前两个人
* 5. 将两个队伍合并为一个队伍
* 6. 根据姓名创建Person对象
* 7. 打印整个队伍的Person信息
*/
public static void main(String[] args) {
List<String> list1 = Arrays.asList("迪丽热巴", "宋远桥", "苏星河", "老子",
"庄子", "孙子", "洪七 公");
List<String> list2 = Arrays.asList("古力娜扎", "张无忌", "张三丰", "赵丽颖",
"张二狗", "张天爱", "张三");
// 1. 第一个队伍只保留姓名长度为3的成员
// 2. 第一个队伍筛选之后只要前3个人
Stream<String> stream1 = list1.stream().filter(s -> s.length() ==
3).limit(3);
// 3. 第二个队伍只要姓张的成员
// 4. 第二个队伍筛选之后不要前两个人
Stream<String> stream2 = list2.stream().filter(s ->
s.startsWith("张")).skip(2);
// 5. 将两个队伍合并为一个队伍
// 6. 根据姓名创建Person对象
// 7. 打印整个队伍的Person信息
Stream.concat(stream1, stream2)
.map(Person::new)
.forEach(System.out::println);
}
public static void main(String[] args) {
List<String> list = Stream.of("aa", "bb", "cc", "aa")
.collect(Collectors.toList());
System.out.println(list);
// 收集到 Set集合中
Set<String> set = Stream.of("aa", "bb", "cc", "aa")
.collect(Collectors.toSet());
System.out.println(set);
// 如果需要获取的类型为具体的实现,比如:ArrayList HashSet
ArrayList<String> arrayList = Stream.of("aa", "bb", "cc", "aa")
.collect(Collectors.toCollection(ArrayList<String>::new));
System.out.println(arrayList);
HashSet<String> hashSet = Stream.of("aa", "bb", "cc", "aa")
.collect(Collectors.toCollection(HashSet<String>::new));
System.out.println(hashSet);
}
Stream
中提供了toArray
方法来将结果放到一个数组中,返回值类型是Object[]
,如果我们要指定返回的类型,那么可以使用另一个重载的toArray(IntFunction f)
方法
public static void main(String[] args) {
Object[] objects = Stream.of("aa", "bb", "cc", "aa")
// 返回的数组中的元素是 Object类型
.toArray();
System.out.println(Arrays.toString(objects));
// 如果我们需要指定返回的数组中的元素类型
String[] strings = Stream.of("aa", "bb", "cc", "aa")
.toArray(String[]::new);
System.out.println(Arrays.toString(strings));
}
我们使用
Stream
流处理数据后,可以像数据库的聚合函数一样对某个字段进行操作,比如获得最大值,最小值,求和,平均值,统计数量。
public static void main(String[] args) {
// 获取年龄的最大值
Optional<Person> maxAge = Stream.of(
new Person("张三", 18)
, new Person("李四", 22)
, new Person("张三", 13)
, new Person("王五", 15)
, new Person("张三", 19)
).max(Comparator.comparingInt(Person::getAge));
System.out.println("最大年龄:" + maxAge.get());
// 获取年龄的最小值
Optional<Person> minAge = Stream.of(
new Person("张三", 18)
, new Person("李四", 22)
, new Person("张三", 13)
, new Person("王五", 15)
, new Person("张三", 19)
).min(Comparator.comparingInt(Person::getAge));
System.out.println("最新年龄:" + minAge.get());
// 求所有人的年龄之和
int sumAge = Stream.of(
new Person("张三", 18)
, new Person("李四", 22)
, new Person("张三", 13)
, new Person("王五", 15)
, new Person("张三", 19)
).mapToInt(Person::getAge).sum();
System.out.println("年龄总和:" + sumAge);
// 年龄的平均值
Double avgAge = Stream.of(
new Person("张三", 18)
, new Person("李四", 22)
, new Person("张三", 13)
, new Person("王五", 15)
, new Person("张三", 19)
).collect(Collectors.averagingInt(Person::getAge));
System.out.println("年龄的平均值:" + avgAge);
// 统计数量
long count = Stream.of(
new Person("张三", 18)
, new Person("李四", 22)
, new Person("张三", 13)
, new Person("王五", 15)
, new Person("张三", 19)
).filter(p -> p.getAge() > 18).count();
System.out.println("满足条件的记录数:" + count);
}
public static void main(String[] args) {
// 根据账号对数据进行分组
Map<String, List<Person>> map1 = Stream.of(
new Person("张三", 18, 175)
, new Person("李四", 22, 177)
, new Person("张三", 14, 165)
, new Person("李四", 15, 166)
, new Person("张三", 19, 182)
).collect(Collectors.groupingBy(Person::getName));
map1.forEach((k, v) -> System.out.println("k=" + k + "\t" + "v=" + v));
System.out.println("-----------");
// 根据年龄分组 如果大于等于18 成年否则未成年
Map<String, List<Person>> map2 = Stream.of(
new Person("张三", 18, 175)
, new Person("李四", 22, 177)
, new Person("张三", 14, 165)
, new Person("李四", 15, 166)
, new Person("张三", 19, 182)
).collect(Collectors.groupingBy(p -> p.getAge() >= 18 ? "成年" : "未成年"));
map2.forEach((k, v) -> System.out.println("k=" + k + "\t" + "v=" + v));
}
多级分组: 先根据
name
分组然后根据年龄分组
public static void main(String[] args) {
// 先根据name分组,然后根据age(成年和未成年)分组
Map<String, Map<Object, List<Person>>> map = Stream.of(
new Person("张三", 18, 175)
, new Person("李四", 22, 177)
, new Person("张三", 14, 165)
, new Person("李四", 15, 166)
, new Person("张三", 19, 182)
).collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(p -> p.getAge() >= 18 ? "成年" : "未成年")));
map.forEach((k, v) -> {
System.out.println(k);
v.forEach((k1, v1) -> {
System.out.println("\t" + k1 + "=" + v1);
});
});
}
Collectors.partitioningBy
会根据值是否为true
,把集合中的数据分割为两个列表,一个true
列表,一个false
列表
public static void main(String[] args) {
Map<Boolean, List<Person>> map = Stream.of(
new Person("张三", 18, 175)
, new Person("李四", 22, 177)
, new Person("张三", 14, 165)
, new Person("李四", 15, 166)
, new Person("张三", 19, 182)
).collect(Collectors.partitioningBy(p -> p.getAge() > 18));
map.forEach((k, v) -> System.out.println(k + "\t" + v));
}
Collectors.joining
会根据指定的连接符,将所有的元素连接成一个字符串
public static void main(String[] args) {
String s1 = Stream.of(
new Person("张三", 18, 175)
, new Person("李四", 22, 177)
, new Person("张三", 14, 165)
, new Person("李四", 15, 166)
, new Person("张三", 19, 182)
).map(Person::getName).collect(Collectors.joining());
// 张三李四张三李四张三
System.out.println(s1);
String s2 = Stream.of(
new Person("张三", 18, 175)
, new Person("李四", 22, 177)
, new Person("张三", 14, 165)
, new Person("李四", 15, 166)
, new Person("张三", 19, 182)
).map(Person::getName).collect(Collectors.joining("_"));
// 张三_李四_张三_李四_张三
System.out.println(s2);
String s3 = Stream.of(
new Person("张三", 18, 175)
, new Person("李四", 22, 177)
, new Person("张三", 14, 165)
, new Person("李四", 15, 166)
, new Person("张三", 19, 182)
).map(Person::getName).collect(Collectors.joining("_", "###", "$$$"));
// ###张三_李四_张三_李四_张三$$$
System.out.println(s3);
}
介绍并行
Stream
流之前先介绍一下串行的Stream
流,我们前面使用的Stream
流都是串行,也就是在一个线程上面执行
public static void main(String[] args) {
System.out.println(Stream.of(5, 6, 8, 3, 1, 6)
.filter(s -> {
System.out.println(Thread.currentThread() + "" + s);
return s > 3;
}).count());
}
parallelStream
其实就是一个并行执行的流,它通过默认的ForkJoinPool
,可以提高多线程任务的速 度。
我们可以通过两种方式来获取并行流
集合
接口中的parallelStream
方法来获取parallel
)public static void main(String[] args) {
System.out.println(Stream.of(1, 4, 2, 6, 1, 5, 9)
// 将流转换为并发流,Stream处理的时候就会通过多线程处理
.parallel()
.filter(s -> {
System.out.println(Thread.currentThread() + " s=" + s);
return s > 2;
}).count());
}
Stream
并行处理的过程会分而治之,也就是将一个大的任务切分成了多个小任务,这表示每个任务都是 一个线程操作。
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
list.add(i);
}
System.out.println(list.size());
List<Integer> listNew = new ArrayList<>();
// 使用并行流来向集合中添加数据
list.parallelStream()
.forEach(listNew::add);
System.out.println(listNew.size());
}
观察上述代码,可能会导致
listNew
长度小于1000
或直接报ArrayIndexOutOfBoundsException
,解决办法有三种:
public static void main(String[] args) {
List<Integer> listNew = new ArrayList<>();
Object obj = new Object();
IntStream.rangeClosed(1, 1000)
.parallel()
.forEach(i -> {
synchronized (obj) {
listNew.add(i);
}
});
System.out.println(listNew.size());
}
public static void main(String[] args) {
List<Integer> listNew = new ArrayList<>();
Object obj = new Object();
IntStream.rangeClosed(1, 1000)
.parallel()
.forEach(i -> {
synchronized (obj) {
listNew.add(i);
}
});
System.out.println(listNew.size());
}
public static void main(String[] args) {
List<Integer> listNew = new ArrayList<>();
Object obj = new Object();
List<Integer> list = IntStream.rangeClosed(1, 1000)
.parallel()
.boxed()
.collect(Collectors.toList());
System.out.println(list.size());
}
Optional
是一个没有子类的工具类,Optional
是一个可以为null
的容器对象,它的主要作用就是为了避 免Null
检查,防止NullpointerException
,
此方法不支持传入
null
值
Optional<String> op1 = Optional.of("zhangsan");
此方法支持传入
null
值
Optional<String> op3 = Optional.ofNullable("lisi");
Optional<Object> op4 = Optional.ofNullable(null);
直接创建一个空的
Optional
对象
Optional
如果
Optional
有值则返回,否则抛出NoSuchElementException
异常get()
通常和isPresent()
方法一块使用
public static void main(String[] args) {
// create a Optional
Optional<Integer> op = Optional.of(9455);
// print value
System.out.println("Optional: " + op);
// get the value
System.out.println("Value of this Optional: " + op.get());
}
判断是否包含值,包含值返回
true
,不包含值返回false
public static void main(String[] args) {
Optional<String> name = Optional.of("Dolores");
Optional<String> empty = Optional.empty();
//如果值不为null,orElse方法返回Optional实例的值。
//如果为null,返回传入的消息。
//输出:Dolores
System.out.println(name.orElse("There is some value!"));
//输出:There is no value present!
System.out.println(empty.orElse("There is no value present!"));
}
如果调用对象包含值,就返回该值,否则返回
t
public static void main(String[] args) {
Person p = new Person("zhangsan", 18);
Optional<Person> op = Optional.of(p);
String name = getNameForOptional(op);
System.out.println("name=" + name);
}
/**
* 根据Person对象 将name转换为大写并返回
* 通过Optional方式实现
*/
public static String getNameForOptional(Optional<Person> op) {
if (op.isPresent()) {
return op.map(Person::getName)
.map(String::toUpperCase)
.orElse("空值");
}
return null;
}
如果调用对象包含值,就返回该值,否则返回
Lambda
表达式的返回值
public static void main(String[] args) {
Optional<String> name = Optional.of("Dolores");
Optional<String> empty = Optional.empty();
//orElseGet与orElse方法类似,区别在于orElse传入的是默认值,
//orElseGet可以接受一个lambda表达式生成默认值。
//输出:Dolores
System.out.println(name.orElseGet(() -> "it's value"));
//输出:No value
System.out.println(empty.orElseGet(() -> "No value"));
}
在使用
Lambda
表达式的时候,也会出现代码冗余的情况,比如:用Lambda
表达式求一个数组的和
public static void main(String[] args) {
printSum(a -> {
// Lambda表达式中的代码和 getTotal中的代码冗余了
int sum = 0;
for (int i : a) {
sum += i;
}
System.out.println("数组之和:" + sum);
});
}
public static void getTotal(int[] a) {
int sum = 0;
for (int i : a) {
sum += i;
}
System.out.println("数组之和:" + sum);
}
private static void printSum(Consumer<int[]> consumer) {
int[] a = {10, 20, 30, 40, 50, 60};
consumer.accept(a);
}
因为在
Lambda
表达式中要执行的代码和我们另一个方法中的代码是一样的,这时就没有必要重写一份逻辑了,这时我们就可以“引用”重复代码
public static void main(String[] args) {
printSum(a -> {
printSum(Main::getTotal);
});
}
public static void getTotal(int[] a) {
int sum = 0;
for (int i : a) {
sum += i;
}
System.out.println("数组之和:" + sum);
}
private static void printSum(Consumer<int[]> consumer) {
int[] a = {10, 20, 30, 40, 50, 60};
consumer.accept(a);
}
这是最常见的一种用法。如果一个类中的已经存在了一个成员方法,则可以通过对象名引用成员方法
public static void main(String[] args) {
Date now = new Date();
Supplier<Long> supplier = () -> {
return now.getTime();
};
System.out.println(supplier.get());
// 然后我们通过 方法引用 的方式来处理
Supplier<Long> supplier1 = now::getTime;
System.out.println(supplier1.get());
}
public static void main(String[] args) {
Supplier<Long> supplier1 = ()->{
return System.currentTimeMillis();
};
System.out.println(supplier1.get());
// 通过 方法引用 来实现
Supplier<Long> supplier2 = System::currentTimeMillis;
System.out.println(supplier2.get());
}
Java
面向对象中,类名只能调用静态方法,类名引用实例方法是用前提的,实际上是拿第一个参数作 为方法的调用者
public static void main(String[] args) {
Function<String, Integer> function = (s) -> {
return s.length();
};
System.out.println(function.apply("hello"));
// 通过方法引用来实现
Function<String, Integer> function1 = String::length;
System.out.println(function1.apply("hahahaha"));
BiFunction<String, Integer, String> function2 = String::substring;
String msg = function2.apply("HelloWorld", 3);
System.out.println(msg);
}
Java
面向对象中,类名只能调用静态方法,类名引用实例方法是用前提的,实际上是拿第一个参数作 为方法的调用者
public static void main(String[] args) {
Supplier<Person> sup = ()->{return new Person();};
System.out.println(sup.get());
// 然后通过 方法引用来实现
Supplier<Person> sup1 = Person::new;
System.out.println(sup1.get());
BiFunction<String,Integer,Person> function = Person::new;
System.out.println(function.apply("张三",22));
}
public static void main(String[] args) {
Supplier<Person> sup = () -> {
return new Person();
};
System.out.println(sup.get());
// 然后通过 方法引用来实现
Supplier<Person> sup1 = Person::new;
System.out.println(sup1.get());
BiFunction<String, Integer, Person> function = Person::new;
System.out.println(function.apply("张三", 22));
}