(参数列表)->{代码}
使用匿名内部类的写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("使用匿名内部类的写法创建线程并启动");
}
},"t1").start();
使用Lambda表达式的写法
new Thread(()->{
System.out.println("使用Lambda表达式创建线程并启动");
},"t2").start();
public static int calculateNum(IntBinaryOperator operator){
int a=10;
int b=20;
return operator.applyAsInt(a,b);
}
使用匿名内部类的写法
int i = calculateNum(new IntBinaryOperator() {
@Override
public int applyAsInt(int left, int right) {
return left + right;
}
});
使用Lambda表达式的写法
int j = calculateNum((int left, int right) -> {
return left + right;
});
System.out.println(j);
public static void printNum(IntPredicate predicate){
int[] arr={1,2,3,4,5,6,7,8,9,10};
for(int i:arr){
if(predicate.test(i)){
System.out.println(i);
}
}
}
使用匿名内部类的写法
printNum(new IntPredicate() {
@Override
public boolean test(int value) {
return value%2==0;
}
});
使用Lambda表达式的写法
printNum((value)->{
return value%2==0;
});
public static <R> R typeConver(Function<String,R> function){
String str="123";
R result=function.apply(str);
return result;
}
使用匿名内部类的写法
Integer ii = typeConver(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
});
System.out.println(ii);
使用Lambda表达式的写法
Integer jj = typeConver((String str) -> {
return Integer.parseInt(str);
});
System.out.println(jj);
public static void foreachArr(IntConsumer consumer){
int[] arr={1,2,3,4,5,6,7,8,9,10};
for(int i:arr){
consumer.accept(i);
}
}
使用匿名内部类的写法
foreachArr(new IntConsumer() {
@Override
public void accept(int value) {
System.out.println(value);
}
});
使用Lambda表达式的写法
foreachArr((value)->{
System.out.println(value);
});
new Thread(()-> System.out.println("使用Lambda表达式创建线程并启动"),"t3").start();
calculateNum((left, right) -> left + right);
printNum(value->value%2==0);
typeConver(str -> Integer.parseInt(str));
foreachArr(value-> System.out.println(value));
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>compile</scope>
</dependency>
package com.technologystatck.lambdas;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LambdaDemo2Stream {
public static void main(String[] args) {
List<Author> authors=getAuthors();
System.out.println(authors);
}
private static List<Author> getAuthors(){
Author author1 = new Author(1L, "张三", 18, "一个热爱《三国演义》的男人", null);
Author author2 = new Author(1L, "张三", 18, "一个热爱《三国演义》的男人", null);
Author author3 = new Author(3L, "王", 38, "一个热爱《西游记》的男人", null);
Author author4 = new Author(4L, "赵六", 16, "一个热爱《红楼梦》的男人", null);
//书籍列表
ArrayList<Book> books1 = new ArrayList<>();
ArrayList<Book> books2 = new ArrayList<>();
ArrayList<Book> books3 = new ArrayList<>();
books1.add(new Book(1L,"books1-《三国演义》","四大名著,历史演义小说",100,"中国四大名著之一"));
books1.add(new Book(2L,"books1-《水浒传》","四大名著,英雄传奇小说",88,"中国四大名著之一"));
books1.add(new Book(3L,"books1-《西游记》","四大名著,神魔小说",99,"中国四大名著之一"));
books1.add(new Book(4L,"books1-《红楼梦》","四大名著,世情小说",66,"中国四大名著之一"));
books2.add(new Book(1L,"books2-《三国演义》","四大名著,历史演义小说",77,"中国四大名著之一"));
books2.add(new Book(2L,"books2-《水浒传》","四大名著,英雄传奇小说",55,"中国四大名著之一"));
books2.add(new Book(3L,"books2-《西游记》","四大名著,神魔小说",66,"中国四大名著之一"));
books2.add(new Book(4L,"books2-《红楼梦》","四大名著,世情小说",88,"中国四大名著之一"));
books3.add(new Book(1L,"books1-《三国演义》","四大名著,历史演义小说",33,"中国四大名著之一"));
books3.add(new Book(2L,"books1-《水浒传》","四大名著,英雄传奇小说",99,"中国四大名著之一"));
books3.add(new Book(3L,"books1-《西游记》","四大名著,神魔小说",22,"中国四大名著之一"));
books3.add(new Book(4L,"books1-《红楼梦》","四大名著,世情小说",100,"中国四大名著之一"));
author1.setBooks(books1);
author2.setBooks(books1);
author3.setBooks(books2);
author4.setBooks(books3);
List<Author> arrayList = new ArrayList<>(Arrays.asList(author1,author2,author3,author4));
return arrayList;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
class Author{
//id
private Long id;
//姓名
private String name;
//年龄
private Integer age;
//简介
private String intro;
//作品
private List<Book> books;
@Override
public String toString() {
return "\nAuthor{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", intro='" + intro + '\'' +
", books=" + books +
'}'+"\n";
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
class Book{
//id
private Long id;
//书名
private String name;
//分类
private String category;
//评分
private Integer score;
//简介
private String intro;
@Override
public String toString() {
return "\nBook{" +
"id=" + id +
", name='" + name + '\'' +
", category='" + category + '\'' +
", score=" + score +
", intro='" + intro + '\'' +
'}';
}
}
集合对象.stream()
List<Author> authors=getAuthors();
Stream<Author> stream=authors.stream();
Arrays.stream(数组)或者使用Stream.of来创建
Integer[] arr={1,2,3,4,5};
Stream<Integer> stream=Arrays.stream(arr);
Stream<Integer> stream2=Stream.of(arr);
转换成单列集合后再创建
Map<String,Integer> map=new HashMap<>();
map.put("蜡笔小新",19);
map.put("小白",4);
map.put("动感超人",29);
Stream<Map.Entry<String,Integer>> stream=map.entrySet().stream();
stream.filter(new Predicate<Map.Entry<String, Integer>>() {
@Override
public boolean test(Map.Entry<String, Integer> stringIntegerEntry) {
return stringIntegerEntry.getValue()>16;
}
}).forEach(stringIntegerEntry -> System.out.println(stringIntegerEntry.getKey()+"="+stringIntegerEntry.getValue()));
可以对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中
/**
* 打印所有姓名长度大于1的作家的姓名
*/
authors.stream()
//去重
.distinct()
//过滤
.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getName().length()>1;
}
})
.forEach(new Consumer<Author>() {
@Override
public void accept(Author author) {
System.out.println(author.getName());
}
可以对流中的元素进行计算或转换
map中第一个泛型必须要跟stream中的类型是一致的,比如这里就要跟authors一个类型
/**
* 打印所有作家的姓名
*/
authors.stream()
.map(new Function<Author, String>() {
@Override
public String apply(Author author) {
return author.getName();
}
})
.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
/**
* 给所有作家的年龄+10
*/
authors.stream()
.map(author->author.getAge())
.map(age->age+10)
.forEach(age-> System.out.println(age));
去除流中的重复元素
依赖于Object的equals方法来判断是否是相同对象的,所以需要注意重写equals方法
@EqualsAndHashCode:该注解替我们重写了equals和hashcode方法
/**
* 打印所有的作家姓名,并且要求其中不能有重复元素
*/
authors.stream()
.distinct()
.forEach(author -> System.out.println(author.getName()));
对流中的元素进行排序
调用空参的sorted()方法,需要实现Comparable,重写compareTo方法
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
class Author implements Comparable<Author>{
//id
private Long id;
//姓名
private String name;
//年龄
private Integer age;
//简介
private String intro;
//作品
private List<Book> books;
@Override
public String toString() {
return "\nAuthor{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", intro='" + intro + '\'' +
", books=" + books +
'}'+"\n";
}
@Override
public int compareTo(Author o) {
return this.getAge()-o.getAge();
}
}
/**
* 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素
*/
authors.stream()
.distinct()
.sorted()
.forEach(author -> System.out.println(author.getAge()));
使用有参方法修改,不需要实现接口
/**
* 使用sorted的有参方法修改
*/
authors.stream()
.distinct()
.sorted(new Comparator<Author>() {
@Override
public int compare(Author o1, Author o2) {
return o1.getAge()-o2.getAge();
}
}).forEach(author -> System.out.println(author.getAge()));
可以设置流的最大长度,超出的部分将被抛弃
/**
* 对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,
* 然后打印其中年龄最大的两个作家的姓名
*/
authors.stream()
.distinct()
.sorted((o1,o2)->o2.getAge()-o1.getAge())
.limit(2)
.forEach(author -> System.out.println(author.getName()));
跳过流中的前n个元素,返回剩下的元素
/**
* 打印除了年龄最大的作家外的其他作家,
* 要求不能有重复元素,并且按照年龄降序排序
*/
authors.stream()
.distinct()
.sorted((o1,o2)->o2.getAge()-o1.getAge())
.skip(1)
.forEach(author -> System.out.println(author));
map只能把一个对象转成另一个对象来作为流中的元素。
而flatMap可以把一个对象转换成多个对象作为流中的元素
/**
* 打印所有书籍的名字,要求对重复的元素进行去重
*/
authors.stream()
.flatMap(new Function<Author, Stream<Book>>() {
@Override
public Stream<Book> apply(Author author) {
return author.getBooks().stream();
}
})
.distinct()
.forEach(new Consumer<Book>() {
@Override
public void accept(Book book) {
System.out.println(book.getName());
}
});
/**
* 打印现有数据的所有分类,要求对分类进行去重
* 不能出现这种格式:四大名著,神魔小说
*/
authors.stream()
.flatMap(author -> author.getBooks().stream())
//对书籍进行去重
.distinct()
.flatMap(new Function<Book, Stream<?>>() {
@Override
public Stream<?> apply(Book book) {
return Arrays.stream(book.getCategory().split(","));
}
})
//对分类进行去重
.distinct()
.forEach(category-> System.out.println(category));
对流中的元素进行遍历操作,通过传入的参数去指定对遍历到的元素进行什么具体的操作
/**
* 输出所有作家的名字
*/
authors.stream()
.map(author -> author.getName())
.distinct()
.forEach(name -> System.out.println(name));
可以用来获取当前流中元素的个数
/**
* 打印这些作家所出书籍的数目,注意删除重复元素
*/
long count = authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.count();
System.out.println(count);
可以用来获取流中的最大 / 小值
/**
* 分别获取这些作家的所出书籍的最高分和最低分并打印
*/
Optional<Integer> max = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println(max.get());
Optional<Integer> min = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.min(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println(min.get());
将当前流转换成一个集合
/**
* 获取一个存放所有作者名字的List集合
*/
List<String> collect = authors.stream()
.map(author -> author.getName())
.distinct()
.collect(Collectors.toList());
for (String s : collect) {
System.out.println(s);
}
/**
* 获取一个存放所有书籍名称的Set集合
*/
Set<String> collect1 = authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.map(book -> book.getName())
.distinct()
.collect(Collectors.toSet());
//模拟一个循环遍历set集合
Iterator<String> iterator = collect1.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.println("next="+next);
}
/**
* 获取一个map集合,map的key为作者名,value为List
*/
Map<String, List<Book>> collect2 = authors.stream()
//key值去重
.distinct()
.collect(Collectors.toMap(new Function<Author, String>() {
@Override
public String apply(Author author) {
return author.getName();
}
}, new Function<Author, List<Book>>() {
@Override
public List<Book> apply(Author author) {
return author.getBooks();
}
}));
Set keySet= collect2.keySet();
Iterator iteratorMap = keySet.iterator();
while (iteratorMap.hasNext()){
Object key = iteratorMap.next();
System.out.println("key="+key+","+"value="+collect2.get(key));
}
可以用来判断是否有任意符合匹配条件的元素,结果为boolean类型
/**
* 判断是否有年龄在29以上的作家
*/
boolean b = authors.stream()
.anyMatch(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge() > 29;
}
});
System.out.println(b);
可以用来判断是否都符合匹配条件,结果为boolean类型
若都符合结果为true,否则结果为false
/**
* 判断是否所有的作家都是成年人
*/
boolean b1 = authors.stream()
.allMatch(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge() >= 18;
}
});
System.out.println(b1);
可以判断流中的元素是否都不符合匹配条件
若都不符合结果为true,否则结果为false
/**
* 判断作家是否都没有超过100岁
*/
boolean b2 = authors.stream()
.noneMatch(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge() > 100;
}
});
System.out.println(b2);
获取流中的任意一个元素
该方法没有办法保证获取的一定是流中的第一个元素
/**
* 获取任意一个年龄大于18的作家,若存在就输出他的名字
*/
Optional<Author> optionalAuthor = authors.stream()
.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge()>18;
}
})
.findAny();
//方式1:
System.out.println(optionalAuthor.get().getName());
//方式2:
optionalAuthor.ifPresent(new Consumer<Author>() {
@Override
public void accept(Author author) {
System.out.println(author.getName());
}
});
获取流中的第一个元素
/**
* 获取一个年龄最小的作家,并输出他的姓名
*/
Optional<Author> first = authors.stream()
.sorted((age1, age2) -> age1.getAge() - age2.getAge())
.distinct()
.findFirst();
first.ifPresent(author -> author.getName());
对流中的数据按照自己制定的计算方式计算出一个结果
reduce的作用是把stream中的元素给组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素和在初始化值的基础上进行计算,计算结果在和后面的元素计算
内部的计算方式如下
T result = identity;
for(T element: this stream)
result=accmulator.apply(result,element)
return result;
可以看作是
int[] arr={1,2,3,4,5,6,7,8,9,10};
int sum=0;
for(int i:arr){
sum+=i;
}
System.out.println(sum);
其中identity就是我们可以通过方法参数传入的初始值,accumulator的apply具体进行什么计算也是我们通过方法参数来确定的
reduce两个参数的重载形式
/**
* 使用reduce求所有作者年龄的和
*/
Integer sums = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(0, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer result, Integer element) {
//result:相当于定义的变量
//element:相当于集合中的元素
return result + element;
}
});
System.out.println(sums);
/**
* 使用reduce求所有作者中年龄的最大值
*/
Integer max = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer result, Integer element) {
return result < element ? element : result;
}
});
System.out.println(max);
/**
* 使用reduce求所有作者中年龄的最小值
*/
Integer min = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(Integer.MAX_VALUE, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer result, Integer element) {
return result > element ? element : result;
}
});
System.out.println(min);
boolean foundAny=false;
T result=null;
for(T element : this stream){
if(!foundAny){
foundAny = true;
result = element;
}else{
result = accumulator.apply(result,element);
}
}
return foundAny ? Optional.of(result) : Optional.empty();
/**
* 使用reduce求所有作者中年龄的最小值
*/
Optional<Integer> reduce = authors.stream()
.map(author -> author.getAge())
.reduce(new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer result, Integer element) {
return result > element ? element : result;
}
});
reduce.ifPresent(age -> System.out.println(age));
惰性求值(如果没有终结操作,没有中间操作是不会得到执行的)
流是一次性的(一旦一个流对象经过一个终结操作(forEach、count、max、min、collect、查找与匹配)后,这个流就不能再被使用)
不会影响原数据(我们在流中可以多数据做很多处理。但是正常情况下是不会影响原来集合中的元素的)
即不调用set方法等
在我们编写代码的时候,出现最多的就是空指针异常,所以在很多情况下我们需要做各种非空的判断
将数据封装成Optional当中的一个属性
例如
Author author = getAuthor();
if(author != null){
System.out.println(author.getName());
}
尤其是对象中的属性还是一个对象的情况下,这种判断会更多
而过多的判断语句会让我们的代码显得臃肿不堪
所以在JDK8中引入了Optional,养成使用Optional的习惯后,可以通过写出更优雅的代码来避免空指针异常
并且在很多函数式编程相关的API中也都用到了Optional,若不会使用Optional也会对函数式编程的学习造成影响
Optional就像是包装类,可以把我们的具体数据封装Optional对象内部,然后我们去使用Optional中封装好的方法操作 封装进去的数据,就可以非常优雅的避免空指针的异常
一般使用Optional的静态方法ofNullable来把数据封装成一个Optional对象。无论传入的参数是否为null都不会出现问题
Author author = getAuthor();
Optional<Author> authorOptional = Optional.ofNullable(author);
package com.technologystatck.lambdas;
import java.util.Optional;
public class LambdaDemo3Optional {
public static void main(String[] args) {
Author author = getAuthor();
//即时getAuthor返回的值为null,也不会出现报错
Optional<Author> authorOptional = Optional.ofNullable(author);
authorOptional.ifPresent(authors-> System.out.println(authors.getName()));
}
public static Author getAuthor(){
Author author = new Author(1L, "马奇", 22, "著有《11111》", null);
return author;
}
}
还可以改造getAuthor方法,让其返回值就是封装好的Optional的话,就可以在使用时方便很多
package com.technologystatck.lambdas;
import java.util.Optional;
import java.util.function.Consumer;
public class LambdaDemo3Optional {
public static void main(String[] args) {
// Author author = getAuthor();
//
// Optional authorOptional = Optional.ofNullable(author);
// authorOptional.ifPresent(authors-> System.out.println(authors.getName()));
Optional<Author> authorOptional = getAuthorOptional();
authorOptional.ifPresent(new Consumer<Author>() {
@Override
public void accept(Author author) {
System.out.println(author.getName());
}
});
}
// public static Author getAuthor(){
// Author author = new Author(1L, "马奇", 22, "著有《11111》", null);
// return author;
// }
public static Optional<Author> getAuthorOptional(){
Author author = new Author(1L, "马奇", 22, "著有《11111》", null);
return Optional.ofNullable(author);
}
}
而且在实际开发中我们的数据很多是从数据库获取的,MyBatis从3.5版本也已经支持Optional了,可以直接把dao方法的返回值类型定义为Optional类型,MyBatis会自己将数据封装成Optional对象返回,封装的过程也不需要我们自己操作
若确定一个对象不是空的则可以使用Optional的静态方法of来把数据封装成Optional对象
Author author = new Author();
Optional<Author> authorOptional = Optional.of(author);
若一个方法的返回值类型是Optional类型,而如果我们经常判断发现某次计算得到的返回值为null,这个时候就需要把null封装成Optional对象返回,这时则可以使用Optional的静态方法empty来进行封装
Optional.empty()
public static Optional<Author> getAuthorOptionals(){
Author author = new Author(1L, "马奇", 22, "著有《11111》", null);
return author==null ? Optional.empty():Optional.of(author);
}
我们获取一个Optional对象后肯定需要对其中的数据进行使用,这时我们可以使用ifPresent方法来消费其中的值,这个方法会判断其内封装的数据是否为空,不为空时才会执行具体的消费代码,这样使用起来就更加安全了
Optional<Author> authorOptional = Optional.ofNullable(getAuthor());
authorOptional.ifPresent(author -> System.out.println(author.getName()));
若想获取值自己进行处理可以使用get方法获取,但是不推荐
因为当Optional内部的数据为空的时候会出现异常
Optional<Author> authorOptional = Optional.ofNullable(getAuthor());
Author author = authorOptional.get();
获取数据并设置数据为空时的默认值,若数据不为空就能获取到该数据,若为空则根据你传入的参数来创建对象作为默认值返回
Optional<Author> authorOptional1 = getAuthorOptional();
Author author = authorOptional1.orElseGet(new Supplier<Author>() {
@Override
public Author get() {
//若值为空,则返回赵八的author
return new Author(2L, "赵八", 33, "著有《22222》", null);
}
});
System.out.println(author.getName());
获取数据,若数据不为空就能获取到该数据,若为空则根据你传入的参数来创建异常抛出
Optional<Author> authorOptional2 = getAuthorOptional();
try {
Author author1 = authorOptional2.orElseThrow(new Supplier<Throwable>() {
@Override
public Throwable get() {
return new RuntimeException("数据为null");
}
});
} catch (Throwable e) {
e.printStackTrace();
}
可以使用filter方法对数据进行过滤,若原本是有数据的,但是不符合判断,也会变成一个无数据的Optional对象
Optional<Author> authorOptional3 = getAuthorOptional();
Optional<Author> author1 = authorOptional3.filter(new Predicate<Author>() {
@Override;
public boolean test(Author author) {
//若年龄大于18就返回true
//若不符合就返回新的Optional,其值为空
return author.getAge() > 18;
}
});
author1.ifPresent(author2-> System.out.println(author2.getName()));
使用isPresent方法进行是否存在数据的判断,
若为空,返回值为false;若不为空,返回值为true,
但是这种方式并不能体现Optional的好处,更推荐使用ifPresent方法
Optional<Author> authorOptional4 = getAuthorOptional();
if(authorOptional4.isPresent()){
System.out.println(authorOptional4.get().getName());
System.out.println(authorOptional4.get().getAge());
}
Optional还提供了map可以让我们对数据进行转换,并且转换得到的数据也还是被Optional包装好的,保证了我们的使用安全
public static Optional<Author> getAuthorOptional(){
Author author = new Author(1L, "马奇", 22, "著有《11111》", null);
ArrayList<Book> books1 = new ArrayList<>();
books1.add(new Book(1L,"books1-《三国演义》","四大名著,历史演义小说",100,"中国四大名著之一"));
books1.add(new Book(2L,"books1-《水浒传》","四大名著,英雄传奇小说",88,"中国四大名著之一"));
books1.add(new Book(3L,"books1-《西游记》","四大名著,神魔小说",99,"中国四大名著之一"));
books1.add(new Book(4L,"books1-《红楼梦》","四大名著,世情小说",66,"中国四大名著之一"));
author.setBooks(books1);
return Optional.ofNullable(author);
}
Optional<Author> authorOptional5 = getAuthorOptional();
Optional<List<Book>> books = authorOptional5.map(author6 -> author6.getBooks());
books.ifPresent(new Consumer<List<Book>>() {
@Override
public void accept(List<Book> books) {
System.out.println(books);
}
});
只有一个抽象方法的接口称之为函数接口
JDK的函数式接口都加上了**@FunctionalInterface**注解进行标识,但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口
在使用Predicate接口时,可能需要进行判断条件的拼接,而and方法相当于是使用 && 来拼接两个判断条件
/**
* 打印作家中年龄大于17并且姓名的长度大于1的作家
*/
authors.stream()
.distinct()
.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge()>17;
}
}.and(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getName().length()>1;
}
}))
.forEach(author -> System.out.println(author.getName()+","+author.getAge()));
printNum(new IntPredicate() {
@Override
public boolean test(int value) {
return value % 2 == 0;
}
}, new IntPredicate() {
@Override
public boolean test(int value) {
return value>5;
}
});
private static void printNum(IntPredicate predicate1,IntPredicate predicate2){
int[] arr={1,2,3,4,5,6,7,8,9,10};
for(int i: arr){
if(predicate1.and(predicate2).test(i)){
System.out.println(i);
}
}
}
在使用Predicate接口时,可能需要进行判断条件的拼接,而or方法相当于时使用 | | 来拼接两个判断条件
/**
* 打印作家中年龄大于17或姓名的长度小于2的作家
*/
authors.stream()
.distinct()
.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge()>17;
}
}.or(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getName().length()<2;
}
}))
.forEach(author -> System.out.println(author.getName()+","+author.getAge()));
在使用Predicate接口时,negate方法相当于是在判断添加前面加了个!表示取反
/**
* 打印作家中年龄不大于17的作家
*/
authors.stream()
.distinct()
.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge()>17;
}
}.negate())
.forEach(author -> System.out.println(author.getName()+","+author.getAge()));
类名或者对象名::方法名
引用类的静态方法
格式
类名: : 方法名
使用前提:
在重写方法时,方法体中只有一行代码,并且这行代码是调用了某个类的静态方法
并且我们要把重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中,就可以引用类的静态方法
List<Author> authors1 = getAuthors();
Stream<Author> stream = authors1.stream();
stream.map(author -> author.getAge())
.map(age->String.valueOf(age));
优化后的写法
stream.map(author-> author.getAge())
.map(String::valueOf);
注意:
引用对象的实例方法
格式
对象名: : 方法名
使用前提:
在重写方法时,方法体中只有一行代码,并且这行代码是调用了某个类的成员方法
并且我们要把重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中,就可以引用对象的实例方法
List<Author> authors2 = getAuthors();
Stream<Author> stream1 = authors2.stream();
StringBuilder sb = new StringBuilder();
stream1.map(author->author.getName())
.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
sb.append(s);
}
});
优化后的方法
stream1.map(author->author.getName())
.forEach(sb::append);
引用类的实例方法
格式
类名: : 方法名
使用前提:
在重写方法时,方法体中只有一行代码,并且这行代码是调用了第一个参数的成员方法
并且我们要把重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中,就可以引用类的实例方法
package com.technologystatck.lambdas;
public class LambdaDemo4Method {
public static void main(String[] args) {
//调用的第一个参数,剩余的参数按顺序传入
subAuthorName("赵八", new UseString() {
@Override
public String use(String str, int start, int length) {
return str.substring(start,length);
}
});
}
public static String subAuthorName(String str,UseString useString){
int start=0;
int length=1;
return useString.use(str,start,length);
}
}
interface UseString{
String use(String str,int start,int length);
}
优化后的方法
package com.technologystatck.lambdas;
public class LambdaDemo4Method {
public static void main(String[] args) {
//调用的第一个参数,剩余的参数按顺序传入
subAuthorName("赵八", String::substring);
}
public static String subAuthorName(String str,UseString useString){
int start=0;
int length=1;
return useString.use(str,start,length);
}
}
interface UseString{
String use(String str,int start,int length);
}
若方法体中的一行代码是构造器的话就可以使用构造器引用
格式:
类名: : new
使用前提:
在重写方法时,方法体中只有一行代码,并且这行代码是调用了某个类的构造方法
并且我们要把重写的抽象方法中所有的参数都按照顺序传入了这个构造方法中,就可以引用构造器
List<Author> authors3 = getAuthors();
authors3.stream()
.map(author -> author.getName())
.map(name->new StringBuilder(name))
.map(sb2->sb2.append("马奇").toString())
.forEach(str-> System.out.println(str));
优化后的方法
List<Author> authors3 = getAuthors();
authors3.stream()
.map(author -> author.getName())
.map(StringBuilder::new)
.map(sb2->sb2.append("马奇").toString())
.forEach(str-> System.out.println(str));
继续优化
List<Author> authors3 = getAuthors();
authors3.stream()
.map(Author::getName)
.map(StringBuilder::new)
.map(sb2->sb2.append("马奇").toString())
.forEach(System.out::println);
之前用到的很多Stream的方法由于都使用了泛型,所以涉及到的参数和返回值都是引用数据类型
即使我们操作的是整数小数,但是实际用的是它们的包装类。
JDK5中引入的自动装箱和自动拆箱让我们在使用对应的包装类时就好像使用基本数据类型一样方便,
但是一定要知道装箱和拆箱肯定是需要消耗时间的,在这个时间的消耗下,大量的数据不断地重复装箱拆箱,就不无视该时间损耗
为了能对这部分时间损耗进行优化,Stream还提供了很多专门针对基本数据类型地方法
mapToInt、mapToLong、mapToDouble、flatMapToInt、flatMapToDouble等
List<Author> authors4 = getAuthors();
authors4.stream()
.map(author -> author.getAge())
.map(age->age+10)
.filter(age->age>18)
.map(age->age+2)
.forEach(System.out::println);
优化后
authors4.stream()
.mapToInt(author->author.getAge())
.map(age->age+10)
.filter(age->age>18)
.map(age->age+2)
.forEach(System.out::println);
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//stream.parallel以多个线程的形式并行执行
Integer sum = stream.parallel()
.peek(new Consumer<Integer>() {
@Override
public void accept(Integer num) {
System.out.println(num+Thread.currentThread().getName());
}
})
.filter(num -> num > 5)
.reduce((result, element) -> result + element)
.get();
System.out.println(sum);
authors4.stream()
.mapToInt(author->author.getAge())
.map(age->age+10)
.filter(age->age>18)
.map(age->age+2)
.forEach(System.out::println);
使用parallelStream()
authors4.parallelStream()
.mapToInt(author->author.getAge())
.map(age->age+10)
.filter(age->age>18)
.map(age->age+2)
.forEach(System.out::println);
使用parallel()
authors4.stream().parallel()
.mapToInt(author->author.getAge())
.map(age->age+10)
.filter(age->age>18)
.map(age->age+2)
.forEach(System.out::println);