面向对象编程:面向对象的语言,一切皆对象,如果想要调用一个函数,函数必须属于一个类或对象,然后在使用类或对象进行调用。面向对象编程会多写很多可能是重复的代码行。
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("do something...");
}
};函数式编程:在某些编程语言中,如js、c++,我们可以直接写一个函数,然后在需要的时候进行调用,即函数式编程。
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, (String a, String b) -> b.compareTo(a));
names.sort((a, b) -> b.compareTo(a));函数式接口(Functional Interface)就是只包含一个抽象方法的接口。只有函数式接口才能缩写成 Lambda 表达式。
@FunctionalInterface //定义为一个函数式接口,如果添加了第二个抽象方法,编译器会立刻抛出错误提示。
interface Converter<F, T> {
T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123Comparator 和 Runnable,Java 8 为他们都添加了 @FunctionalInterface 注解,以用来支持 Lambda 表达式。
指定入参类型,并返回 boolean 值的函数式接口。用来组合一个复杂的逻辑判断。
Predicate<String> predicate = (s) -> s.length() > 0;
predicate.test("foo"); // true
predicate.negate().test("foo"); // false
Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();public class SortTest {
public static void main(String[] args) {
Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName); //升序
Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");
comparator.compare(p1, p2); // > 0 字母升序
comparator.reversed().compare(p1, p2); // < 0 字母降序
List<Person> personList = new ArrayList<>();
personList.add(p1);
personList.add(p2);
personList.stream().sorted(comparator).forEach(System.out::println); //sorted不会改变personList
// personList.sort(comparator); //sort会改变personList
// personList.stream().forEach(System.out::println);
}
}
class Person {
public String firstName;
public String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return this.firstName;
}
}Consumer 接口接收一个泛型参数,然后调用 accept,对这个参数做一系列的操作。
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Consumer<Integer> consumer = x -> {
int a = x + 2;
System.out.println(a);// 12
System.out.println(a + "_");// 12_
};
consumer.accept(10); //调用了accept控制台才会输出主要是对入参做一些操作,在stream里,主要是用于forEach,对传入的参数,做一系列的业务操作。
// CopyOnWriteArrayList
public void forEach(Consumer<? super E> action) {
if (action == null) throw new NullPointerException();
Object[] elements = getArray();
int len = elements.length;
for (int i = 0; i < len; ++i) {
@SuppressWarnings("unchecked") E e = (E) elements[i];
action.accept(e);
}
}
CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
list.add(1);
list.add(2);
//forEach需要传入Consumer参数
list
.stream()
.forEach(System.out::println);
list.forEach(System.out::println);使用 java.util.Stream 对一个包含一个或多个元素的集合做各种操作,原集合不变,返回新集合。只能对实现了 java.util.Collection 接口的类做流的操作。Map 不支持 Stream 流。Stream 流支持同步执行,也支持并发执行。
创建一个 List 集合:
List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");Filter的入参是一个Predicate,用于筛选出我们需要的集合元素。原集合不变。
stringCollection
.stream()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
// "aaa2", "aaa1"自然排序,不改变原集合,返回排序后的集合。
stringCollection
.stream()
.sorted()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
// "aaa1", "aaa2"逆序排序:
stringCollection
.stream()
.sorted(Comparator.reverseOrder());对元素某个字段排序:
list.stream().sorted(Comparator.comparing(Student::getAge).reversed());
list.stream().sorted(Comparator.comparing(Student::getAge));将每个字符串转为大写。
stringCollection
.stream()
.map(String::toUpperCase)
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);
// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"验证 list 中 string 是否有以 a 开头的, 匹配到第一个,即返回 true。
boolean anyStartsWithA =
stringCollection
.stream()
.anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true// 先对 list 中字符串开头为 b 进行过滤,让后统计数量
long startsWithB =
stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();
System.out.println(startsWithB); // 3类似拼接。
Optional<String> reduced =
stringCollection
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"flatMap 用于将多个Stream连接成一个Stream。比如把几个小的list转换到一个大的list。
@Test
public void testMapAndFlatMap() {
List<String> words = new ArrayList<String>();
words.add("hello");
words.add("word");
//将words数组中的元素再按照字符拆分,然后字符去重,最终达到["h", "e", "l", "o", "w", "r", "d"]
//如果使用map,是达不到直接转化成List<String>的结果
List<String> stringList = words.stream()
.flatMap(word -> Arrays.stream(word.split("")))
.distinct()
.collect(Collectors.toList());
stringList.forEach(e -> System.out.println(e));
}
//another demo
//把几个小的list转换到一个大的list。
public class Test {
public static void main(String args[]) {
List<String> teamIndia = Arrays.asList("Virat", "Dhoni", "Jadeja");
List<String> teamAustralia = Arrays.asList("Warner", "Watson", "Smith");
List<String> teamEngland = Arrays.asList("Alex", "Bell", "Broad");
List<List<String>> playersInWorldCup2016 = new ArrayList<>();
playersInWorldCup2016.add(teamIndia);
playersInWorldCup2016.add(teamAustralia);
playersInWorldCup2016.add(teamEngland);
// Now let's do this in Java 8 using FlatMap
List<String> flatMapList = playersInWorldCup2016.stream()
.flatMap(pList -> pList.stream())
.collect(Collectors.toList());
System.out.println(flatMapList);
}
}stream 流是支持顺序和并行的。顺序流操作是单线程操作,而并行流是通过多线程来处理的,处理速度更快。
long count = values.parallelStream().sorted().count();不能在遍历的时候使用map.remove()删除元素,会抛 ConcurrentModificationException 异常。可以使用 iterator.remove() 安全删除数据。使用 lambda 的 removeIf 提前删除数据,或者使用 Stream 的 filter 过滤掉要删除的数据,然后再进行遍历,也是安全的。
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
// 与老版不同的是,putIfAbent() 方法在 put 之前,
// 会判断 key 是否已经存在,存在则直接返回 value, 否则 put, 再返回 value
map.putIfAbsent(i, "val" + i);
}
// forEach 可以很方便地对 map 进行遍历操作
map.forEach((key, value) -> System.out.println(value));
map.entrySet().stream().forEach((entry) -> System.out.println(entry.getKey()));
//遍历前先移除key为1的键值
map.keySet().removeIf(key -> key == 1);
//过滤要删除的值,然后再进行遍历,才是安全的
map.entrySet().stream().filter(m -> 1 != m.getKey()).foreach((entry) -> {});
// computeIfPresent(), 当 key 存在时,才会做相关处理
// 如下:对 key 为 3 的值,内部会先判断值是否存在,存在,则做 value + key 的拼接操作
map.computeIfPresent(3, (num, val) -> val + num);
map.get(3); // val33
// 先判断 key 为 9 的元素是否存在,存在,则做删除操作
map.computeIfPresent(9, (num, val) -> null);
map.containsKey(9); // false
// computeIfAbsent(), 当 key 不存在时,才会做相关处理
// 如下:先判断 key 为 23 的元素是否存在,不存在,则添加
map.computeIfAbsent(23, num -> "val" + num);
map.containsKey(23); // true
// 先判断 key 为 3 的元素是否存在,存在,则不做任何处理
map.computeIfAbsent(3, num -> "bam");
map.get(3); // val33
//只有当给定的 key 和 value 完全匹配时,才会执行删除操作。
map.remove(3, "val3");
map.get(3); // val33
map.remove(3, "val33");
map.get(3); // null
// 若 key 42 不存在,则返回 not found
map.getOrDefault(42, "not found"); // not found
// merge 方法,会先判断进行合并的 key 是否存在,不存在,则会添加元素
map.merge(9, "val9", (value, newValue) -> value.concat(newValue));
map.get(9); // val9
// 若 key 的元素存在,则对 value 执行拼接操作
map.merge(9, "concat", (value, newValue) -> value.concat(newValue));
map.get(9); // val9concat