Lambda表达式
Lambda是一个匿名函数,我们可以把Lambda表达式理解成是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁,更灵活的代码,作为一种更紧凑的代码发风格,使得Java的语言表达能力得到了提升。
Lambda表达式在Java8语言中引入的一种新的语法元素和操作符,这个操作符为"->",该操作符被称为Lambda操作符或者箭头操作符,它将Lambda分为两个部分:
- 左侧:指定了
Lambda表达式需要的参数列表 - 右侧:指定了
Lambda体,是抽象方法的实现逻辑,也即Lambda表达式要执行的功能。
import org.junit.Test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Consumer;
/**
* Lambda表达式的使用
* <p>
* 1.举例: (o1,o2) -> Integer.compare(o1,o2);
* 2.格式:
* -> :lambda操作符 或 箭头操作符
* ->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)
* ->右边:lambda体 (其实就是重写的抽象方法的方法体)
* <p>
* 3. Lambda表达式的使用:(分为6种情况介绍)
* <p>
* 总结:
* ->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也
* 可以省略
* ->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一
对{}和return关键字
* <p>
* 4.Lambda表达式的本质:作为函数式接口的实例
* <p>
* 5. 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上
使用 @FunctionalInterface 注解,
* 这样做可以检查它是否是一个函数式接口。
* <p>
* 6. 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
*/
public class LambdaTest1 {
//语法格式一:无参,无返回值
@Test
public void test1() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("我爱北京天安门");
}
};
r1.run();
System.out.println("***********************");
Runnable r2 = () -> {
System.out.println("我爱北京故宫");
};
r2.run();
}
//语法格式二:Lambda 需要一个参数,但是没有返回值。
@Test
public void test2() {
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("谎言和誓言的区别是什么?");
System.out.println("*******************");
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
con1.accept("一个是听得人当真了,一个是说的人当真了");
}
//语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
@Test
public void test3() {
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
con1.accept("一个是听得人当真了,一个是说的人当真了");
System.out.println("*******************");
Consumer<String> con2 = (s) -> {
System.out.println(s);
};
con2.accept("一个是听得人当真了,一个是说的人当真了");
}
@Test
public void test4() {
ArrayList<String> list = new ArrayList<>();//类型推断
int[] arr = {1, 2, 3};//类型推断
}
//语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
@Test
public void test5() {
Consumer<String> con1 = (s) -> {
System.out.println(s);
};
con1.accept("一个是听得人当真了,一个是说的人当真了");
System.out.println("*******************");
Consumer<String> con2 = s -> {
System.out.println(s);
};
con2.accept("一个是听得人当真了,一个是说的人当真了");
}
//语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
@Test
public void test6() {
Comparator<Integer> com1 = 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(com1.compare(12, 21));
System.out.println("*****************************");
Comparator<Integer> com2 = (o1, o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(com2.compare(12, 6));
}
//语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
@Test
public void test7() {
Comparator<Integer> com1 = (o1, o2) -> {
return o1.compareTo(o2);
};
System.out.println(com1.compare(12, 6));
System.out.println("*****************************");
Comparator<Integer> com2 = (o1, o2) -> o1.compareTo(o2);
System.out.println(com2.compare(12, 21));
}
@Test
public void test8() {
Consumer<String> con1 = s -> {
System.out.println(s);
};
con1.accept("一个是听得人当真了,一个是说的人当真了");
System.out.println("*****************************");
Consumer<String> con2 = s -> System.out.println(s);
con2.accept("一个是听得人当真了,一个是说的人当真了");
}
}
内置四大函数接口
消费型接口: Consumer< T> void accept(T t)有参数,无返回值的抽象方法;
/**
* 消费型接口
*/
public class ConsumerInterface {
public static void main(String[] args) {
Consumer<String> stringConsumer = new Consumer<String>() {
@Override
public void accept(String str) {
System.out.println(str);
}
};
//Lambda表达式简化
Consumer<String> consumer =(str)->{System.out.println(str);};
consumer.accept("打印str");
}
}
供给型接口: Supplier < T> T get() 无参有返回值的抽象方法;
/**
* 供给型接口
*/
public class SupplierInterface {
public static void main(String[] args) {
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "供给型接口";
}
};
//Lambda表达式简化
Supplier<String> sp =()->{return "供给型接口";};
System.out.println(sp.get());
}
断定型接口: Predicate boolean test(T t):有参,但是返回值类型是固定的boolean;
/**
* Predicate
*有一个输入参数,返回值只能是boolean值,用于做判断
*/
public static void main(String[] args) {
//可以来做判断字符串是否为空
Predicate pc = new Predicate<String>() {
@Override
public boolean test(String str) {
return str.isEmpty();
}
};
System.out.println(pc.test("qwew"));
//Lambda表达式简化
Predicate<String> pre =(str)->{return str.isEmpty(); };
System.out.println(pre.test(""));
}
函数型接口: Function<T,R> R apply(T t)有参有返回值的抽象方法;
/**
* Function
*有参数,有返回值
*/
public static void main(String[] args) {
Function function = new Function<String, String>() {
@Override
public String apply(String str) {
return str;
}
};
//Lambda表达式简化
Function<String, String> function2 = (str) -> {return str; };
System.out.println(function2.apply("asd"));
}
Stream流
我们可以使用 java.util.Stream 对一个包含一个或多个元素的集合做各种操作。这些操作可能是 中间操作 亦或是 终端操作。 终端操作会返回一个结果,而中间操作会返回一个 Stream 流。
Stream流的方法详解
forEach
forEach()方法遍历流中的元素
void forEach(Consumer<? super T> action)
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.stream().forEach((str)->{
System.out.println(str);
});
//简写
list.stream().forEach(System.out::println);
Filter
筛选过滤出符合指定条件的元素
public static void main(args[]){
List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
System.out.println("Languages which starts with J :");
filter(languages, (str)->str.startsWith("J"));
System.out.println("Languages which ends with a ");
filter(languages, (str)->str.endsWith("a"));
System.out.println("Print all languages :");
filter(languages, (str)->true);
System.out.println("Print no language : ");
filter(languages, (str)->false);
System.out.println("Print language whose length greater than 4:");
filter(languages, (str)->str.length() > 4);
}
public static void filter(List names, Predicate condition) {
names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
System.out.println(name + " ");
});
}
Predicate
// 可以用and()、or()和xor()逻辑函数来合并Predicate,
// 例如要找到所有以J开始,长度为四个字母的名字,你可以合并两个Predicate并传入
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
names.stream()
.filter(startsWithJ.and(fourLetterLong))
.forEach((n) -> System.out.print("nName, which starts with 'J' and four letter long is : " + n));
limit
从流中筛选出前n个元素
Stream<T> limit(long maxSize);
//筛选出流中前两个元素
list.stream().limit(2).forEach(System.out::println);
map
map()方法,将流中的元素映射到另外一个流中
//该方法需要一个Function型函数式接口,将当前流中T类型的数据转换成R类型的流
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
public static void main(String[] args) {
Stream.of("1", "2", "3", "4", "5")
.map(Integer::parseInt)
.forEach(System.out::println);
Stream.of(6,7,8,9,10)
.map(String::valueOf)
.forEach(System.out::println);
}
skip
跳过前面n个元素,进行截取
Stream<T> skip(long n);
使用:
public static void main(String[] args) {
Stream.of("a", "b", "c", "d", "a", "b", "a", "c")
.skip(5)
//.skip(-1) 报错
//.skip(10)
.forEach(System.out::println);
}
concat
concat()方法,Stream接口中的静态方法,合并两个流
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
Objects.requireNonNull(a);
Objects.requireNonNull(b);
@SuppressWarnings("unchecked")
Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
(Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
return stream.onClose(Streams.composedClose(a, b));
}
使用:
List<Integer> list = new ArrayList<>();
list.add(12);
list.add(8);
list.add(4);
list.add(13);
Stream<Integer> stream1 = list.stream().filter((str) -> {
return str > 12;
});
Stream<Integer> stream2 = list.stream().filter((str) -> {
return str < 5;
});
Stream.concat(stream1, stream2).forEach(System.out::println); //13 4
reduce
将所有数据归纳得到一个数据
T reduce(T identity, BinaryOperator<T> accumulator);
使用:
public static void main(String[] args) {
Integer sum = Stream.of("1", "2", "3", "4", "5","1","1","2")
.map(Integer::parseInt)
// identity:默认值
// 第一次的时候会将默认值赋值给a
// 之后每次都会将上次的结果赋值给a,b接收流中的数据
.reduce(0, (a, b) -> {
System.out.print("a = " + a);
System.out.println(" b = " + b);
return a + b;
});
System.out.println("sum = " + sum);
// 获取最大值:
Integer max = Stream.of("1", "2", "3", "4", "5")
.map(Integer::parseInt)
.reduce(0, (a, b) -> a > b ? a : b);
//.reduce(1, Math::max);
System.out.println("max = "+max);
// 统计 1 出现的次数
Integer count = Stream.of("1", "2", "3", "4", "5", "1", "1", "2")
.map(s -> "1".equals(s) ? 1 : 0)
.reduce(0, Integer::sum);
System.out.println(count);
}
max,min
max:获取最大值
Optional<T> max(Comparator<? super T> comparator);
min:获取最小值
Optional<T> min(Comparator<? super T> comparator);
使用:
public static void main(String[] args) {
Optional<Integer> max = Stream.of("1", "2", "3", "4", "5")
.map(Integer::parseInt)
.max(Comparator.comparingInt(o -> o));
// .max((o1,o2)->o1-o2);等价
System.out.println("max = "+max.get());
Optional<Integer> min = Stream.of("1", "2", "3", "4", "5")
.map(Integer::parseInt)
.min((o1,o2)->o1-o2);
System.out.println("min = "+min.get());
}
distinct
除去重复的元素
Stream<T> distinct();
使用:
public static void main(String[] args) {
Stream<String> distinct = Stream.of("a", "b", "c", "d", "a", "b", "a", "c")
.distinct();
distinct.forEach(System.out::println);
// 需要在Student类中重写equals和hashcode方法,才能去掉重复的数据
Stream.of(new Student("张三",18),
new Student("李四",20),
new Student("张三",18),
new Student("王五",22),
new Student("李四",20))
.distinct()
.forEach(System.out::println);
}
allMatch、anyMatch、nonMatch
allMatch()、anyMatch()、nonMatch()方法,判断数据是否匹配指定条件
//allMatch():元素是否全部都匹配条件
boolean allMatch(Predicate<? super T> predicate);
//anyMatch():元素是否有任意一个匹配条件
boolean anyMatch(Predicate<? super T> predicate);
//nonMatch():元素是否全部都不满足条件
boolean noneMatch(Predicate<? super T> predicate);
使用:
List<Integer> list = new ArrayList<>();
list.add(13);
list.add(12);
list.add(8);
list.add(4);
boolean b1 = list.stream().allMatch((n) -> {return n > 8;});//false
boolean b2 = list.stream().anyMatch((n) -> {return n > 8;});//true
boolean b3 = list.stream().noneMatch((n) -> {return n > 8;});//false
sorted
sorted()方法,对流中的数据进行排序
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
使用:
List<Integer> list = new ArrayList<>();
list.add(13);
list.add(12);
list.add(8);
list.add(4);
list.stream().sorted((str1,str2)->(str1-str2)).forEach(System.out::println);
count
用来计算元素的个数,返回一个long类型的值,代表元素的个数
long count();
使用:
public static void main(String[] args) {
long count = Stream.of("a", "b", "c", "d", "a", "b", "a", "c")
.count();
System.out.println("元素的个数为:"+count);
}
peek
List<Person> lists = new ArrayList<Person>();
lists.add(new Person(1L, "p1"));
lists.add(new Person(2L, "p2"));
lists.add(new Person(3L, "p3"));
lists.add(new Person(4L, "p4"));
System.out.println(lists);
List<Person> list2 = lists.stream()
.filter(f -> f.getName().startsWith("p"))
.peek(t -> {
System.out.println(t.getName());
})
.collect(Collectors.toList());
System.out.println(list2);
mapToInt
mapToInt()方法,将Stream流中的Integer类型的元素转换成int类型
IntStream mapToInt(ToIntFunction<? super T> mapper);
使用:
List<Integer> list = new ArrayList<>();
list.add(12);
list.add(8);
list.add(4);
list.add(13);
list.stream().mapToInt(new ToIntFunction<Integer>() {
@Override
public int applyAsInt(Integer value) {
return value;
}
}).forEach(System.out::println);