2 changed files with 114 additions and 162 deletions
@ -0,0 +1,96 @@ |
|||
public class Car { |
|||
// 1. 私有成员变量(封装核心:隐藏内部数据)
|
|||
private String brand; // 品牌
|
|||
private String model; // 型号
|
|||
private int year; // 生产年份
|
|||
private double price; // 价格
|
|||
|
|||
// 2. 无参构造方法(构造方法重载 1)
|
|||
public Car() { |
|||
// 默认值
|
|||
this.brand = "未知品牌"; |
|||
this.model = "未知型号"; |
|||
this.year = 2020; |
|||
this.price = 0.0; |
|||
} |
|||
|
|||
// 3. 带参构造方法(构造方法重载 2:只传入品牌和型号)
|
|||
public Car(String brand, String model) { |
|||
this.brand = brand; |
|||
this.model = model; |
|||
this.year = 2020; // 默认年份
|
|||
this.price = 0.0; // 默认价格
|
|||
} |
|||
|
|||
// 4. 全参构造方法(构造方法重载 3:传入所有属性,含数据校验)
|
|||
public Car(String brand, String model, int year, double price) { |
|||
this.brand = brand; |
|||
this.model = model; |
|||
// 数据校验:年份必须在 1900~2026 之间
|
|||
if (year >= 1900 && year <= 2026) { |
|||
this.year = year; |
|||
} else { |
|||
System.out.println("年份输入不合法,已设置为默认值 2020"); |
|||
this.year = 2020; |
|||
} |
|||
// 数据校验:价格不能为负数
|
|||
if (price >= 0) { |
|||
this.price = price; |
|||
} else { |
|||
System.out.println("价格输入不合法,已设置为默认值 0.0"); |
|||
this.price = 0.0; |
|||
} |
|||
} |
|||
|
|||
// 5. 公共 getter/setter 方法(封装核心:提供受控访问)
|
|||
public String getBrand() { |
|||
return brand; |
|||
} |
|||
|
|||
public void setBrand(String brand) { |
|||
this.brand = brand; |
|||
} |
|||
|
|||
public String getModel() { |
|||
return model; |
|||
} |
|||
|
|||
public void setModel(String model) { |
|||
this.model = model; |
|||
} |
|||
|
|||
public int getYear() { |
|||
return year; |
|||
} |
|||
|
|||
public void setYear(int year) { |
|||
// 校验年份
|
|||
if (year >= 1900 && year <= 2026) { |
|||
this.year = year; |
|||
} else { |
|||
System.out.println("年份输入不合法,未修改"); |
|||
} |
|||
} |
|||
|
|||
public double getPrice() { |
|||
return price; |
|||
} |
|||
|
|||
public void setPrice(double price) { |
|||
// 校验价格
|
|||
if (price >= 0) { |
|||
this.price = price; |
|||
} else { |
|||
System.out.println("价格输入不合法,未修改"); |
|||
} |
|||
} |
|||
|
|||
// 6. 显示车辆信息的方法
|
|||
public void showInfo() { |
|||
System.out.println("=== 车辆信息 ==="); |
|||
System.out.println("品牌:" + this.brand); |
|||
System.out.println("型号:" + this.model); |
|||
System.out.println("生产年份:" + this.year); |
|||
System.out.println("价格:" + this.price + " 万"); |
|||
} |
|||
} |
|||
@ -1,169 +1,25 @@ |
|||
import org.jfree.chart.ChartFactory; |
|||
import org.jfree.chart.ChartUtils; |
|||
import org.jfree.chart.JFreeChart; |
|||
import org.jfree.data.category.DefaultCategoryDataset; |
|||
import org.jfree.data.general.DefaultPieDataset; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileWriter; |
|||
import java.io.IOException; |
|||
import java.util.*; |
|||
import java.util.stream.Collectors; |
|||
|
|||
public class Main { |
|||
public static void main(String[] args) { |
|||
try { |
|||
// 1. 爬取电影数据
|
|||
MovieCrawler crawler = new MovieCrawler(); |
|||
List<Movie> movies = crawler.crawlTopMovies(50); // 爬取50部电影
|
|||
|
|||
// 2. 数据清洗
|
|||
List<Movie> cleanedMovies = cleanData(movies); |
|||
|
|||
// 3. 数据存储
|
|||
saveToCSV(cleanedMovies, "movies.csv"); |
|||
|
|||
// 4. 数据分析
|
|||
analyzeData(cleanedMovies); |
|||
|
|||
// 5. 结果展示
|
|||
displayResults(cleanedMovies); |
|||
generateCharts(cleanedMovies); |
|||
|
|||
System.out.println("爬取完成!共获取了 " + cleanedMovies.size() + " 部电影数据。"); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
private static List<Movie> cleanData(List<Movie> movies) { |
|||
return movies.stream() |
|||
.map(movie -> { |
|||
// 去空格
|
|||
movie.setTitle(movie.getTitle().trim()); |
|||
movie.setGenre(movie.getGenre().trim()); |
|||
movie.setDirector(movie.getDirector().trim()); |
|||
movie.setActors(movie.getActors().trim()); |
|||
movie.setSynopsis(movie.getSynopsis().trim()); |
|||
return movie; |
|||
}) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
|
|||
private static void saveToCSV(List<Movie> movies, String fileName) throws IOException { |
|||
try (FileWriter writer = new FileWriter(fileName)) { |
|||
// 写入表头
|
|||
writer.write("Title,Year,Rating,Genre,Director,Actors,Synopsis\n"); |
|||
|
|||
// 写入数据
|
|||
for (Movie movie : movies) { |
|||
writer.write(String.format("%s,%d,%.1f,%s,%s,%s,%s\n", |
|||
escapeCSV(movie.getTitle()), |
|||
movie.getYear(), |
|||
movie.getRating(), |
|||
escapeCSV(movie.getGenre()), |
|||
escapeCSV(movie.getDirector()), |
|||
escapeCSV(movie.getActors()), |
|||
escapeCSV(movie.getSynopsis()))); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static String escapeCSV(String value) { |
|||
if (value == null) return ""; |
|||
if (value.contains(",") || value.contains("\n") || value.contains("\"")) { |
|||
value = value.replace("\"", "\"\""); |
|||
return "\"" + value + "\""; |
|||
} |
|||
return value; |
|||
} |
|||
// 测试 1:无参构造
|
|||
Car car1 = new Car(); |
|||
car1.showInfo(); |
|||
|
|||
private static void analyzeData(List<Movie> movies) { |
|||
System.out.println("\n=== 数据分析结果 ==="); |
|||
|
|||
// 1. 评分分布
|
|||
System.out.println("\n1. 评分分布:"); |
|||
Map<Double, Long> ratingDistribution = movies.stream() |
|||
.collect(Collectors.groupingBy(Movie::getRating, Collectors.counting())); |
|||
ratingDistribution.entrySet().stream() |
|||
.sorted(Map.Entry.comparingByKey()) |
|||
.forEach(entry -> System.out.printf("评分 %.1f: %d 部\n", entry.getKey(), entry.getValue())); |
|||
|
|||
// 2. 年份分布
|
|||
System.out.println("\n2. 年份分布:"); |
|||
Map<Integer, Long> yearDistribution = movies.stream() |
|||
.collect(Collectors.groupingBy(Movie::getYear, Collectors.counting())); |
|||
yearDistribution.entrySet().stream() |
|||
.sorted(Map.Entry.comparingByKey()) |
|||
.forEach(entry -> System.out.printf("年份 %d: %d 部\n", entry.getKey(), entry.getValue())); |
|||
|
|||
// 3. 导演作品数排行
|
|||
System.out.println("\n3. 导演作品数排行:"); |
|||
Map<String, Long> directorCount = movies.stream() |
|||
.collect(Collectors.groupingBy(Movie::getDirector, Collectors.counting())); |
|||
directorCount.entrySet().stream() |
|||
.sorted(Map.Entry.<String, Long>comparingByValue().reversed()) |
|||
.limit(10) |
|||
.forEach(entry -> System.out.printf("%s: %d 部\n", entry.getKey(), entry.getValue())); |
|||
|
|||
// 4. 平均评分
|
|||
double averageRating = movies.stream() |
|||
.mapToDouble(Movie::getRating) |
|||
.average() |
|||
.orElse(0); |
|||
System.out.printf("\n4. 平均评分:%.2f\n", averageRating); |
|||
} |
|||
// 测试 2:带参构造(品牌+型号)
|
|||
Car car2 = new Car("Toyota", "Camry"); |
|||
car2.showInfo(); |
|||
|
|||
private static void displayResults(List<Movie> movies) { |
|||
System.out.println("\n=== 电影数据列表 ==="); |
|||
System.out.printf("%-50s %-10s %-10s %-30s %-30s\n", "Title", "Year", "Rating", "Genre", "Director"); |
|||
System.out.println("-------------------------------------------------------------------------------------------------------------------------------"); |
|||
|
|||
for (Movie movie : movies) { |
|||
System.out.printf("%-50s %-10d %-10.1f %-30s %-30s\n", |
|||
truncate(movie.getTitle(), 50), |
|||
movie.getYear(), |
|||
movie.getRating(), |
|||
truncate(movie.getGenre(), 30), |
|||
truncate(movie.getDirector(), 30)); |
|||
} |
|||
} |
|||
// 测试 3:全参构造(合法数据)
|
|||
Car car3 = new Car("Tesla", "Model 3", 2024, 28.9); |
|||
car3.showInfo(); |
|||
|
|||
private static String truncate(String text, int maxLength) { |
|||
return text.length() > maxLength ? text.substring(0, maxLength - 3) + "..." : text; |
|||
} |
|||
// 测试 4:全参构造(非法数据,触发校验)
|
|||
Car car4 = new Car("BYD", "Han", 1899, -20.0); |
|||
car4.showInfo(); |
|||
|
|||
private static void generateCharts(List<Movie> movies) throws IOException { |
|||
// 1. 评分分布饼图
|
|||
DefaultPieDataset ratingDataset = new DefaultPieDataset(); |
|||
Map<Double, Long> ratingDistribution = movies.stream() |
|||
.collect(Collectors.groupingBy(Movie::getRating, Collectors.counting())); |
|||
ratingDistribution.forEach((rating, count) -> ratingDataset.setValue(String.valueOf(rating), count)); |
|||
|
|||
JFreeChart ratingChart = ChartFactory.createPieChart( |
|||
"电影评分分布", |
|||
ratingDataset, |
|||
true, |
|||
true, |
|||
false |
|||
); |
|||
ChartUtils.saveChartAsPNG(new File("rating_distribution.png"), ratingChart, 800, 600); |
|||
|
|||
// 2. 年份与评分关系图
|
|||
DefaultCategoryDataset yearRatingDataset = new DefaultCategoryDataset(); |
|||
Map<Integer, Double> yearAverageRating = movies.stream() |
|||
.collect(Collectors.groupingBy(Movie::getYear, |
|||
Collectors.averagingDouble(Movie::getRating))); |
|||
yearAverageRating.forEach((year, avgRating) -> yearRatingDataset.addValue(avgRating, "评分", String.valueOf(year))); |
|||
|
|||
JFreeChart yearRatingChart = ChartFactory.createBarChart( |
|||
"年份与平均评分关系", |
|||
"年份", |
|||
"平均评分", |
|||
yearRatingDataset |
|||
); |
|||
ChartUtils.saveChartAsPNG(new File("year_rating_relation.png"), yearRatingChart, 800, 600); |
|||
|
|||
System.out.println("\n图表已生成:rating_distribution.png 和 year_rating_relation.png"); |
|||
// 测试 5:通过 setter 修改并校验
|
|||
car4.setYear(2025); |
|||
car4.setPrice(25.9); |
|||
System.out.println("修改后:"); |
|||
car4.showInfo(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue