是一种匿名函数,可以简化代码,常用于函数式编程。它们允许你将函数作为参数传递给其他函数。
理解 Lambda 表达式的基本概念,可以类比为在日常生活中使用快递服务。
想象你需要给朋友发送一些东西,但你不想亲自去邮局。你可以使用快递服务,这时 Lambda 表达式就像是给快递员的指令。
// 传统的匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Sending a package to friend.");
}
}).start();
// 使用Lambda表达式
new Thread(() -> System.out.println("Sending a package to friend.")).start();
假设你想给朋友寄一个生日礼物:
假设你有一个 GiftSender 接口,它只有一个方法 sendGift():
interface GiftSender {
void sendGift();
}
GiftSender sender = new GiftSender() {
@Override
public void sendGift() {
System.out.println("Sending a birthday gift to friend.");
}
};
sender.sendGift();
GiftSender sender = () -> System.out.println("Sending a birthday gift to friend.");
sender.sendGift();
总结
通过这种类比,你可以更形象地理解Lambda表达式是如何简化代码的。它让你能够直接给出指令,而不是定义一个完整的类来实现这个简单的任务。
只有一个抽象方法的接口。Lambda 表达式通常用于实现这些接口的唯一抽象方法。
理解 Lambda 函数式接口,可以类比为在餐馆点菜的过程。
想象你走进了一家自助餐馆,你可以选择不同的服务方式:
假设你想点一份沙拉:
假设有一个FoodPreparer接口,它只有一个抽象方法 prepareFood():
interface FoodPreparer {
void prepareFood();
}
就像你告诉服务员你想要什么:
// 传统方式
FoodPreparer preparer = new FoodPreparer() {
@Override
public void prepareFood() {
System.out.println("Preparing a salad.");
}
};
preparer.prepareFood();
就像你直接去自助餐台:
// Lambda方式
FoodPreparer preparer = () -> System.out.println("Preparing a salad.");
preparer.prepareFood();
假设你想创建一个简单的应用,让用户可以选择不同的操作:
interface Operation {
void execute();
}
// 定义一个操作
Operation add = () -> System.out.println("Adding numbers");
// 执行这个操作
add.execute();
总结
通过这种类比,你可以形象地理解:
基本语法:
(参数列表) -> { 代码块 }
参数类型推断:如果编译器可以推断出参数类型,可以省略类型。
(x) -> System.out.println(x);
单参数简写:如果只有一个参数,可以省略括号。
x -> System.out.println(x);
无参数:
() -> System.out.println("Hello");
返回值:如果只有一行代码且是返回值,可以省略 return 和花括号。
x -> x * x; // 等同于 (x) -> { return x * x; }
作为方法参数:
Arrays.asList("a", "b", "c").forEach(e -> System.out.println(e));
实现函数式接口:
Runnable r = () -> System.out.println("My Runnable");
// 传统方式
class BookBorrowResult implements BorrowCallback {
@Override
public void onBorrowResult(String result) {
System.out.println("Borrow result: " + result);
}
}
Library.borrowBook("Java Programming", new BookBorrowResult());
// Lambda方式
Library.borrowBook("Java Programming", result -> System.out.println("Borrow result: " + result));
class CoffeeReadyListener implements CoffeeCallback {
@Override
public void onCoffeeReady() {
System.out.println("Your coffee is ready!");
}
}
CoffeeShop.orderCoffee("Espresso", new CoffeeReadyListener());
CoffeeShop.orderCoffee("Espresso", () -> System.out.println("Your coffee is ready!"));
class LightOn implements Runnable {
@Override
public void run() {
System.out.println("Turning the light on at 7 PM.");
}
}
Timer timer = new Timer();
timer.schedule(new LightOn(), 7 * 60 * 60 * 1000); // 7 PM
Timer timer = new Timer();
timer.schedule(() -> System.out.println("Turning the light on at 7 PM."), 7 * 60 * 60 * 1000);
class FileProcessor implements LineProcessor {
@Override
public void processLine(String line) {
System.out.println("Line read: " + line);
}
}
// 假设有一个FileReader类
FileReader reader = new FileReader("example.txt");
reader.processFile(new FileProcessor());
FileReader reader = new FileReader("example.txt");
reader.processFile(line -> System.out.println("Line read: " + line));
通过这些类比,你可以更形象地理解:
理解Lambda表达式的使用场景,可以通过日常生活中的一些任务来类比。以下是一些形象的例子:
// 传统方式
class NewspaperSubscriber implements Runnable {
@Override
public void run() {
System.out.println("Delivering newspaper weekly.");
}
}
new Thread(new NewspaperSubscriber()).start();
// Lambda方式
new Thread(() -> System.out.println("Delivering newspaper weekly.")).start();
// 传统方式
class WaterPlants implements Runnable {
@Override
public void run() {
System.out.println("Watering plants at 6 AM.");
}
}
Timer timer = new Timer();
timer.schedule(new WaterPlants(), 6 * 60 * 60 * 1000); // 6 AM
// Lambda方式
Timer timer = new Timer();
timer.schedule(() -> System.out.println("Watering plants at 6 AM."), 6 * 60 * 60 * 1000);
// 传统方式
class EmailProcessor implements Runnable {
@Override
public void run() {
System.out.println("Processing new email.");
}
}
// 假设有一个邮件系统
EmailSystem emailSystem = new EmailSystem();
emailSystem.setEmailListener(new EmailProcessor());
// Lambda方式
EmailSystem emailSystem = new EmailSystem();
emailSystem.setEmailListener(() -> System.out.println("Processing new email."));
// 传统方式
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 10, 15, 20);
List<Integer> filteredList = new ArrayList<>();
for (Integer number : numbers) {
if (number > 10) {
filteredList.add(number);
}
}
// Lambda方式
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 10, 15, 20);
List<Integer> filteredList = numbers.stream()
.filter(x -> x > 10)
.collect(Collectors.toList());
// 传统方式
JButton button = new JButton("Click me");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked!");
}
});
// Lambda方式
JButton button = new JButton("Click me");
button.addActionListener(e -> System.out.println("Button clicked!"));
这些例子展示了Lambda表达式如何简化代码:
通过这些类比,你可以更形象地理解Lambda表达式的使用场景:它们用于简化代码,提供直接的、简洁的任务实现。
方法引用(Method Reference)是一种简化 Lambda 表达式的写法,可以直接引用现有的方法或构造函数。
List<String> list = Arrays.asList("a", "b", "c");
list.forEach(System.out::println); // 调用System.out.println方法
在编程中,Lambda 方法引用就像是创建了一个快捷方式,直接引用现有的方法。
场景:打印所有字符串
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));
names.forEach(System.out::println);
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Person> people = names.stream()
.map(name -> new Person(name))
.collect(Collectors.toList());
List<Person> people = names.stream()
.map(Person::new)
.collect(Collectors.toList());
List<String> strings = Arrays.asList("hello", "world");
List<String> upperCaseStrings = strings.stream()
.map(s -> s.toUpperCase())
.collect(Collectors.toList());
List<String> upperCaseStrings = strings.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
List<String> strings = Arrays.asList("hello", "world");
strings.forEach(s -> System.out.println(s));
strings.forEach(System.out::println);
通过这种类比,你可以更形象地理解:
Consumer:接受一个输入参数,不返回值。
Consumer<String> consumer = s -> System.out.println(s);
Supplier:不接受参数,返回一个结果。
Supplier<String> supplier = () -> "Hello";
Predicate:接受一个参数,返回一个布尔值。
Predicate<String> predicate = s -> s.length() > 5;
Function:接受一个参数,返回一个结果。
Function<String, Integer> toInteger = Integer::valueOf;
深入理解和使用Lambda函数式接口的常用接口,可以通过一些日常生活中的场景来类比。以下是一些形象的例子:
例子:通知服务
class NotificationService {
public void notify(String message) {
System.out.println("Notifying: " + message);
}
}
NotificationService service = new NotificationService();
service.notify("Party tonight!");
List<String> friends = Arrays.asList("Alice", "Bob", "Charlie");
friends.forEach(friend -> System.out.println("Notifying " + friend + ": Party tonight!"));
List<String> friends = Arrays.asList("Alice", "Bob", "Charlie");
Consumer<String> notify = System.out::println;
friends.forEach(friend -> notify.accept("Notifying " + friend + ": Party tonight!"));
例子:天气预报
class WeatherService {
public String getWeather() {
return "Sunny";
}
}
WeatherService service = new WeatherService();
String weather = service.getWeather();
System.out.println("Today's weather: " + weather);
Supplier<String> weatherSupplier = () -> "Sunny";
String weather = weatherSupplier.get();
System.out.println("Today's weather: " + weather);
例子:筛选朋友
class FriendFilter {
public boolean isNameLongEnough(String name) {
return name.length() > 5;
}
}
List<String> friends = Arrays.asList("Alice", "Bob", "Charlie", "David");
FriendFilter filter = new FriendFilter();
List<String> longNameFriends = friends.stream()
.filter(filter::isNameLongEnough)
.collect(Collectors.toList());
List<String> friends = Arrays.asList("Alice", "Bob", "Charlie", "David");
Predicate<String> longNamePredicate = name -> name.length() > 5;
List<String> longNameFriends = friends.stream()
.filter(longNamePredicate)
.collect(Collectors.toList());
例子:转换货币
class CurrencyConverter {
public double convertToEuro(double dollars) {
return dollars * 0.85; // 假设汇率为0.85
}
}
CurrencyConverter converter = new CurrencyConverter();
double euros = converter.convertToEuro(100);
System.out.println("100 USD in EUR: " + euros);
Function<Double, Double> toEuro = dollars -> dollars * 0.85;
double euros = toEuro.apply(100.0);
System.out.println("100 USD in EUR: " + euros);
例子:通知朋友和时间
class NotificationService {
public void notify(String friend, String time) {
System.out.println(friend + " should be ready at " + time);
}
}
NotificationService service = new NotificationService();
service.notify("Alice", "8 PM");
BiConsumer<String, String> notify = (friend, time) -> System.out.println(friend + " should be ready at " + time);
notify.accept("Alice", "8 PM");
例子:计算朋友聚会费用
class PartyCostCalculator {
public double calculateCost(int foodQuantity, double pricePerItem) {
return foodQuantity * pricePerItem;
}
}
PartyCostCalculator calculator = new PartyCostCalculator();
double cost = calculator.calculateCost(3, 5.99);
System.out.println("Cost: $" + cost);
BiFunction<Integer, Double, Double> calculateCost = (quantity, price) -> quantity * price;
double cost = calculateCost.apply(3, 5.99);
System.out.println("Cost: $" + cost);
这些例子展示了如何通过日常生活中的场景来理解和使用Lambda函数式接口:
通过这些类比,你可以更形象地理解这些接口的作用,并在实际编程中灵活使用它们。
用于处理集合数据的 API,常与 Lambda 表达式结合使用。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().filter(x -> x % 2 == 0).mapToInt(x -> x).sum();
理解和使用 Lambda 流(Stream API)可以类比为在现实生活中处理一系列物品或信息的流程。
List<Book> books = Arrays.asList(
new Book("Java Programming", "Computer"),
new Book("1984", "Fiction"),
new Book("Algorithms", "Computer")
);
List<Book> computerBooks = new ArrayList<>();
for (Book book : books) {
if ("Computer".equals(book.getCategory())) {
computerBooks.add(book);
}
}
List<Book> books = Arrays.asList(
new Book("Java Programming", "Computer"),
new Book("1984", "Fiction"),
new Book("Algorithms", "Computer")
);
List<Book> computerBooks = books.stream()
.filter(book -> "Computer".equals(book.getCategory()))
.collect(Collectors.toList());
List<Order> orders = Arrays.asList(
new Order("Espresso", 3.5),
new Order("Latte", 4.5),
new Order("Mocha", 6.0)
);
List<Order> expensiveOrders = new ArrayList<>();
for (Order order : orders) {
if (order.getPrice() > 5) {
expensiveOrders.add(order);
}
}
List<Order> orders = Arrays.asList(
new Order("Espresso", 3.5),
new Order("Latte", 4.5),
new Order("Mocha", 6.0)
);
List<Order> expensiveOrders = orders.stream()
.filter(order -> order.getPrice() > 5)
.collect(Collectors.toList());
List<Student> students = Arrays.asList(
new Student("Alice", 85),
new Student("Bob", 70),
new Student("Charlie", 60)
);
List<Student> passedStudents = new ArrayList<>();
double sum = 0;
int count = 0;
for (Student student : students) {
if (student.getScore() >= 60) {
passedStudents.add(student);
sum += student.getScore();
count++;
}
}
double average = count > 0 ? sum / count : 0;
List<Student> students = Arrays.asList(
new Student("Alice", 85),
new Student("Bob", 70),
new Student("Charlie", 60)
);
double average = students.stream()
.filter(student -> student.getScore() >= 60)
.mapToInt(Student::getScore)
.average()
.orElse(0);
File directory = new File("/path/to/directory");
File[] files = directory.listFiles();
List<File> largeFiles = new ArrayList<>();
for (File file : files) {
if (file.isFile() && file.length() > 1_000_000) {
largeFiles.add(file);
}
}
File directory = new File("/path/to/directory");
List<File> largeFiles = Arrays.stream(directory.listFiles())
.filter(File::isFile)
.filter(file -> file.length() > 1_000_000)
.collect(Collectors.toList());
List<String> data = Arrays.asList(" hello ", " world ", " java ");
List<String> cleanedData = new ArrayList<>();
for (String s : data) {
cleanedData.add(s.trim().toUpperCase());
}
List<String> data = Arrays.asList(" hello ", " world ", " java ");
List<String> cleanedData = data.stream()
.map(String::trim)
.map(String::toUpperCase)
.collect(Collectors.toList());
这些例子展示了如何通过日常生活中的场景来理解和使用Stream API:
通过这些类比,你可以更形象地理解 Stream API 的作用:
Stream API 简化了数据处理,使得代码更加简洁、易读,并且可以更方便地进行并行处理。
利用多核处理器提高性能。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream().filter(x -> x % 2 == 0).mapToInt(x -> x).sum();
理解和使用 Lambda 表达式与并行处理,可以类比为在现实生活中进行大规模任务的分发和处理。
List<Book> books = Arrays.asList(
new Book("Java Programming", "Computer"),
new Book("1984", "Fiction"),
new Book("Algorithms", "Computer")
);
Map<String, List<Book>> categorizedBooks = new HashMap<>();
for (Book book : books) {
String category = book.getCategory();
if (!categorizedBooks.containsKey(category)) {
categorizedBooks.put(category, new ArrayList<>());
}
categorizedBooks.get(category).add(book);
}
List<Book> books = Arrays.asList(
new Book("Java Programming", "Computer"),
new Book("1984", "Fiction"),
new Book("Algorithms", "Computer")
);
Map<String, List<Book>> categorizedBooks = books.parallelStream()
.collect(Collectors.groupingBy(Book::getCategory));
List<Order> orders = Arrays.asList(
new Order("Espresso", 3.5),
new Order("Latte", 4.5),
new Order("Mocha", 6.0)
);
double totalPrice = 0;
for (Order order : orders) {
totalPrice += order.getPrice();
}
List<Order> orders = Arrays.asList(
new Order("Espresso", 3.5),
new Order("Latte", 4.5),
new Order("Mocha", 6.0)
);
double totalPrice = orders.parallelStream()
.mapToDouble(Order::getPrice)
.sum();
List<File> files = Arrays.asList(new File("file1"), new File("file2"), new File("file3"));
List<File> largeFiles = new ArrayList<>();
for (File file : files) {
if (file.length() > 1_000_000_000) {
largeFiles.add(file);
}
}
List<File> files = Arrays.asList(new File("file1"), new File("file2"), new File("file3"));
List<File> largeFiles = files.parallelStream()
.filter(file -> file.length() > 1_000_000_000)
.collect(Collectors.toList());
List<User> users = Arrays.asList(
new User("Alice", 100), // 活跃度
new User("Bob", 20),
new User("Charlie", 500)
);
List<User> activeUsers = new ArrayList<>();
for (User user : users) {
if (user.getActivity() > 100) {
activeUsers.add(user);
}
}
List<User> users = Arrays.asList(
new User("Alice", 100),
new User("Bob", 20),
new User("Charlie", 500)
);
List<User> activeUsers = users.parallelStream()
.filter(user -> user.getActivity() > 100)
.collect(Collectors.toList());
List<String> data = Arrays.asList(" hello ", " world ", " java ");
List<String> cleanedData = new ArrayList<>();
for (String s : data) {
cleanedData.add(s.trim().toUpperCase());
}
int count = 0;
for (String s : cleanedData) {
if (s.contains("O")) {
count++;
}
}
List<String> data = Arrays.asList(" hello ", " world ", " java ");
long count = data.parallelStream()
.map(String::trim)
.map(String::toUpperCase)
.filter(s -> s.contains("O"))
.count();
这些例子展示了如何通过日常生活中的场景来理解和使用Lambda表达式与并行处理:
通过这些类比,你可以更形象地理解:
并行处理通过分发任务到多个处理单元(如CPU核心),可以显著提高大规模数据处理的效率。特别是在处理大量数据时,Lambda表达式与并行流的结合可以极大地提升程序的性能。
Lambda 表达式中处理异常需要使用 try-catch 块。
Runnable r = () -> {
try {
// 代码可能抛出异常
} catch (Exception e) {
// 异常处理
}
};
理解和使用 Lambda 表达式与异常处理,可以类比为在日常生活中处理突发情况或错误。
class Library {
public Book borrowBook(String title) throws BookNotFoundException {
// 模拟借书过程
if (!books.contains(title)) {
throw new BookNotFoundException("Book not found: " + title);
}
return new Book(title);
}
}
// 使用
try {
Book book = library.borrowBook("Java Programming");
System.out.println("Borrowed: " + book.getTitle());
} catch (BookNotFoundException e) {
System.out.println("Error: " + e.getMessage());
}
Optional<Book> book = Optional.ofNullable(library.borrowBook("Java Programming"))
.map(b -> {
try {
return b;
} catch (BookNotFoundException e) {
System.out.println("Error: " + e.getMessage());
return null;
}
});
book.ifPresent(b -> System.out.println("Borrowed: " + b.getTitle()));
List<String> apiUrls = Arrays.asList("api1", "api2", "api3");
for (String url : apiUrls) {
try {
String response = fetchDataFromAPI(url);
System.out.println("Data from " + url + ": " + response);
} catch (IOException e) {
System.out.println("Failed to fetch data from " + url + ": " + e.getMessage());
}
}
List<String> apiUrls = Arrays.asList("api1", "api2", "api3");
apiUrls.forEach(url -> {
try {
String response = fetchDataFromAPI(url);
System.out.println("Data from " + url + ": " + response);
} catch (IOException e) {
System.out.println("Failed to fetch data from " + url + ": " + e.getMessage());
}
});
List<String> filePaths = Arrays.asList("file1.txt", "file2.txt", "file3.txt");
for (String path : filePaths) {
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("Line from " + path + ": " + line);
}
} catch (IOException e) {
System.out.println("Failed to read " + path + ": " + e.getMessage());
}
}
List<String> filePaths = Arrays.asList("file1.txt", "file2.txt", "file3.txt");
filePaths.forEach(path -> {
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("Line from " + path + ": " + line);
}
} catch (IOException e) {
System.out.println("Failed to read " + path + ": " + e.getMessage());
}
});
List<String> numbers = Arrays.asList("1", "2", "three", "4");
List<Integer> intNumbers = new ArrayList<>();
for (String num : numbers) {
try {
intNumbers.add(Integer.parseInt(num));
} catch (NumberFormatException e) {
System.out.println("Invalid number: " + num);
}
}
List<String> numbers = Arrays.asList("1", "2", "three", "4");
List<Integer> intNumbers = numbers.stream()
.map(num -> {
try {
return Integer.parseInt(num);
} catch (NumberFormatException e) {
System.out.println("Invalid number: " + num);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
这些例子展示了如何通过日常生活中的场景来理解和使用Lambda表达式与异常处理:
通过这些类比,你可以更形象地理解:
通过这些步骤,你可以从零基础逐步理解和掌握 Lambda 表达式的使用。记住,实践是最好的学习方式,尝试在你的项目中使用 Lambda 表达式来加深理解。
因篇幅问题不能全部显示,请点此查看更多更全内容