Lambda
一、简介
Lambda 表达式是 Java 8 引入的一种新的语法,它允许你以简洁的方式表示可传递给方法或存储在变量中的代码块。Lambda 表达式可以用来替代匿名内部类,使代码更加简洁、易读和易于维护。
二、Lambda 表达式的基本语法
Lambda 表达式的语法形式为:(parameters) -> expression
或 (parameters) -> { statements; }
。
parameters
:参数列表,可以为空,也可以包含一个或多个参数,参数类型可以显式指定,也可以根据上下文推断。expression
:一个表达式,当 Lambda 表达式只有一个表达式时,可以直接使用这个表达式作为返回值。statements
:一个代码块,当 Lambda 表达式需要执行多个语句时,可以使用代码块,并使用return
语句返回结果。
例如:
// 无参数,返回一个固定值
() -> "Hello, Lambda!";
// 一个参数,对参数进行操作并返回结果
x -> x * 2;
// 多个参数,进行复杂的操作并返回结果
(x, y) -> {
int sum = x + y;
return sum * 3;
};
三、Lambda 表达式的类型推断
Java 编译器可以根据上下文推断 Lambda 表达式的参数类型和返回类型。这使得代码更加简洁,不需要显式指定类型。
例如:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.forEach(n -> System.out.println(n));
在这个例子中,编译器可以推断出n
的类型是Integer
,因为numbers
是一个List<Integer>
。
四、Lambda 表达式作为函数式接口的实现
函数式接口是一个只有一个抽象方法的接口。Lambda 表达式可以用来实现函数式接口,使得代码更加简洁。
例如:
@FunctionalInterface
interface MyFunction {
int apply(int x);
}
public class LambdaAsFunctionalInterfaceExample {
public static void main(String[] args) {
MyFunction multiplyByTwo = x -> x * 2;
int result = multiplyByTwo.apply(5);
System.out.println(result);
}
}
在这个例子中,MyFunction
是一个函数式接口,multiplyByTwo
是一个 Lambda 表达式,它实现了MyFunction
接口的apply
方法。
五、Lambda 表达式与方法引用
方法引用是一种简化 Lambda 表达式的方式,它可以直接引用已有的方法。方法引用的语法形式为:ClassName::methodName
。
例如:
List<String> words = Arrays.asList("apple", "banana", "cherry");
words.forEach(System.out::println);
在这个例子中,System.out::println
是一个方法引用,它引用了System.out
对象的println
方法。这个方法引用可以作为forEach
方法的参数,用来遍历并打印列表中的每个元素。
六、Lambda 表达式的应用场景
-
集合的遍历和操作:
- 使用
forEach
方法遍历集合,并对每个元素执行操作。 - 使用
stream
方法将集合转换为流,并进行各种操作,如过滤、映射、排序等。
示例:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.forEach(n -> System.out.println(n)); List<Integer> filteredNumbers = numbers.stream() .filter(n -> n % 2 == 0) .collect(Collectors.toList()); System.out.println(filteredNumbers);
- 使用
-
事件处理:
- 在图形用户界面(GUI)编程中,使用 Lambda 表达式来处理事件,如按钮点击事件、鼠标移动事件等。
示例:
import javax.swing.JButton; import javax.swing.JFrame; public class LambdaInEventHandlingExample { public static void main(String[] args) { JFrame frame = new JFrame("Lambda in Event Handling"); JButton button = new JButton("Click me!"); button.addActionListener(event -> System.out.println("Button clicked!")); frame.add(button); frame.setSize(300, 200); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
-
多线程编程:
- 使用 Lambda 表达式来创建线程,执行异步任务。
示例:
public class LambdaInMultithreadingExample { public static void main(String[] args) { new Thread(() -> System.out.println("Hello from a new thread!")).start(); } }
七、Lambda 表达式的注意事项
- Lambda 表达式只能用于函数式接口,不能用于普通接口或抽象类。
- Lambda 表达式的参数类型和返回类型必须与函数式接口的抽象方法一致。
- Lambda 表达式的代码块中不能声明与函数式接口的抽象方法参数同名的局部变量。
- Lambda 表达式的代码块中不能修改外部变量的值,除非外部变量是
final
或effectively final
(即实际上是不可变的)。
stream
一、简介
Java Stream 是 Java 8 引入的一种处理集合数据的新方式,它可以让你以声明式的方式对集合进行各种操作,如过滤、映射、排序、聚合等,同时可以实现并行处理,提高处理效率。
二、创建 Stream
-
从集合创建 Stream:
- 可以使用集合的
stream()
方法来创建一个顺序流,或者使用parallelStream()
方法来创建一个并行流。 - 示例:
import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class StreamCreationExample { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); numbers.add(1); numbers.add(2); numbers.add(3); numbers.add(4); numbers.add(5); // 创建顺序流 Stream<Integer> stream = numbers.stream(); // 创建并行流 Stream<Integer> parallelStream = numbers.parallelStream(); } }
- 可以使用集合的
-
从数组创建 Stream:
- 可以使用
Arrays.stream()
方法从数组创建一个流。 - 示例:
import java.util.Arrays; import java.util.stream.Stream; public class StreamFromArrayExample { public static void main(String[] args) { int[] array = {1, 2, 3, 4, 5}; Stream<Integer> stream = Arrays.stream(array).boxed(); } }
- 可以使用
-
从其他数据源创建 Stream:
- 例如,可以使用
Stream.of()
方法从一组元素创建一个流。 - 示例:
import java.util.stream.Stream; public class StreamFromElementsExample { public static void main(String[] args) { Stream<String> stream = Stream.of("apple", "banana", "cherry"); } }
- 例如,可以使用
三、中间操作
-
过滤(filter):
filter
方法接受一个Predicate<T>
函数式接口作为参数,用于筛选出满足条件的元素。- 示例:
import java.util.stream.Stream; public class FilterExample { public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5); Stream<Integer> filteredStream = stream.filter(n -> n % 2 == 0); filteredStream.forEach(System.out::println); } }
-
映射(map):
map
方法接受一个Function<T, R>
函数式接口作为参数,用于将每个元素转换为另一个元素。- 示例:
import java.util.stream.Stream; public class MapExample { public static void main(String[] args) { Stream<String> stream = Stream.of("apple", "banana", "cherry"); Stream<Integer> lengthStream = stream.map(String::length); lengthStream.forEach(System.out::println); } }
-
排序(sorted):
- 可以对流中的元素进行自然排序或自定义排序。
- 示例:
import java.util.stream.Stream; public class SortedExample { public static void main(String[] args) { Stream<Integer> stream = Stream.of(5, 3, 1, 4, 2); // 自然排序 Stream<Integer> sortedStream = stream.sorted(); sortedStream.forEach(System.out::println); // 自定义排序 Stream<String> stringStream = Stream.of("apple", "banana", "cherry"); Stream<String> customSortedStream = stringStream.sorted((s1, s2) -> s1.length() - s2.length()); customSortedStream.forEach(System.out::println); } }
-
扁平化(flatMap):
flatMap
方法接受一个Function<T, Stream<R>>
函数式接口作为参数,用于将一个流中的每个元素转换为另一个流,然后将这些流扁平化为一个单一的流。- 示例:
import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class FlatMapExample { public static void main(String[] args) { List<List<Integer>> nestedList = Arrays.asList( Arrays.asList(1, 2), Arrays.asList(3, 4), Arrays.asList(5, 6) ); Stream<Integer> flatStream = nestedList.stream() .flatMap(List::stream); flatStream.forEach(System.out::println); } }
四、终端操作
-
遍历(forEach):
forEach
方法接受一个Consumer<T>
函数式接口作为参数,用于对每个元素执行一个操作。- 示例:
import java.util.stream.Stream; public class ForEachExample { public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5); stream.forEach(n -> System.out.println(n)); } }
-
收集(collect):
collect
方法接受一个Collector<T, A, R>
接口作为参数,用于将流中的元素收集到一个结果容器中,如列表、集合或映射。- 示例:
import java.util.stream.Stream; import java.util.List; import java.util.ArrayList; import java.util.stream.Collectors; public class CollectExample { public static void main(String[] args) { Stream<String> stream = Stream.of("apple", "banana", "cherry"); List<String> list = stream.collect(Collectors.toList()); System.out.println(list); } }
-
聚合操作(reduce):
reduce
方法用于对流中的元素进行归约操作,如求和、求最大值、求最小值等。- 示例:
import java.util.stream.Stream; public class ReduceExample { public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5); Integer sum = stream.reduce(0, (a, b) -> a + b); System.out.println(sum); } }
-
匹配操作(anyMatch、allMatch、noneMatch):
anyMatch
方法用于判断流中是否至少有一个元素满足给定条件。allMatch
方法用于判断流中的所有元素是否都满足给定条件。noneMatch
方法用于判断流中是否没有一个元素满足给定条件。- 示例:
import java.util.stream.Stream; public class MatchExample { public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5); boolean anyEven = stream.anyMatch(n -> n % 2 == 0); boolean allLessThanTen = stream.allMatch(n -> n < 10); boolean noneGreaterThanTen = stream.noneMatch(n -> n > 10); System.out.println("Any even number? " + anyEven); System.out.println("All less than ten? " + allLessThanTen); System.out.println("None greater than ten? " + noneGreaterThanTen); } }
五、并行流
-
并行处理:
- 并行流可以利用多核处理器来并行执行操作,提高处理效率。
- 示例:
import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class ParallelStreamExample { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); for (int i = 1; i <= 1000000; i++) { numbers.add(i); } long startTime = System.currentTimeMillis(); int sumSequential = numbers.stream().reduce(0, Integer::sum); long endTime = System.currentTimeMillis(); System.out.println("Sequential sum: " + sumSequential + " Time taken: " + (endTime - startTime) + " ms"); startTime = System.currentTimeMillis(); int sumParallel = numbers.parallelStream().reduce(0, Integer::sum); endTime = System.currentTimeMillis(); System.out.println("Parallel sum: " + sumParallel + " Time taken: " + (endTime - startTime) + " ms"); } }
-
注意事项:
- 并行流并不总是比顺序流更快,在数据量较小或操作本身开销较大时,并行处理可能会带来额外的开销。
- 在使用并行流时,需要注意操作的线程安全性和副作用。
六、应用场景
-
数据处理和转换:
- 可以使用 Stream 对大量数据进行快速的过滤、映射和转换操作。
- 示例:
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class DataProcessingExample { public static void main(String[] args) { List<String> words = new ArrayList<>(); words.add("apple"); words.add("banana"); words.add("cherry"); words.add("date"); List<String> upperCaseWords = words.stream() .map(String::toUpperCase) .collect(Collectors.toList()); System.out.println(upperCaseWords); } }
-
数据库查询结果处理:
- 可以对从数据库查询得到的结果集进行 Stream 操作,进行筛选、转换和聚合等操作。
- 示例:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class DatabaseProcessingExample { public static List<Integer> queryDatabase() { List<Integer> results = new ArrayList<>(); try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username", "password"); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT id FROM mytable")) { while (resultSet.next()) { results.add(resultSet.getInt("id")); } } catch (SQLException e) { e.printStackTrace(); } return results; } public static void main(String[] args) { List<Integer> ids = queryDatabase(); List<Integer> filteredIds = ids.stream() .filter(id -> id > 100) .collect(Collectors.toList()); System.out.println(filteredIds); } }