杰瑞科技汇

Java如何解决重复代码问题?

Of course! The term "duplicate" in Java can refer to several different concepts. I'll cover the most common ones, from checking for duplicates in data structures to handling duplicate code.

Here’s a breakdown of the main ways "duplicate" is used in Java:

  1. Finding Duplicates in Data Structures (e.g., in an Array or List)
  2. Preventing Duplicates in Collections (e.g., using a Set)
  3. Duplicate Code (a general programming practice issue)
  4. Duplicate Methods/Classes (a compiler error)

Finding Duplicates in Data Structures

This is a very common interview question and a frequent task in applications. The goal is to find if a collection contains any duplicate elements.

Example: Using a List (e.g., ArrayList)

Let's say you have an ArrayList of integers and you want to find the duplicates.

Method 1: Using a HashSet (Most Efficient)

A HashSet is a collection that cannot contain duplicate elements. We can use this property to find duplicates efficiently.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class FindDuplicates {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 2, 5, 6, 1, 7, 8, 8);
        // Use a Set to track seen elements
        Set<Integer> seen = new HashSet<>();
        Set<Integer> duplicates = new HashSet<>(); // Use a Set to store duplicates to avoid printing them multiple times
        for (Integer number : numbers) {
            if (!seen.add(number)) { // add() returns false if the element already exists
                duplicates.add(number);
            }
        }
        System.out.println("Original List: " + numbers);
        System.out.println("Duplicate Elements: " + duplicates); // Output: [1, 2, 8]
    }
}

How it works:

  1. We iterate through the numbers list.
  2. For each number, we try to add it to the seen HashSet.
  3. The add() method of a Set returns true if the element was added, and false if it was already present.
  4. If add() returns false, it means we've found a duplicate, so we add it to our duplicates set.

Method 2: Using Java 8 Streams (Modern & Concise)

Java 8 Streams provide a very elegant way to handle this.

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FindDuplicatesStream {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 2, 5, 6, 1, 7, 8, 8);
        // Group elements by their frequency
        Map<Integer, Long> frequencyMap = numbers.stream()
                .collect(Collectors.groupingBy(
                        Function.identity(),
                        Collectors.counting()
                ));
        // Filter elements with a frequency greater than 1
        List<Integer> duplicates = frequencyMap.entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .toList();
        System.out.println("Original List: " + numbers);
        System.out.println("Duplicate Elements: " + duplicates); // Output: [1, 2, 8]
    }
}

Preventing Duplicates in Collections

Sometimes you don't want to find duplicates; you want to prevent them from being added in the first place. The Set interface is perfect for this.

Example: Using a HashSet

A HashSet automatically handles uniqueness for you.

import java.util.HashSet;
import java.util.Set;
public class PreventDuplicates {
    public static void main(String[] args) {
        Set<String> uniqueNames = new HashSet<>();
        // Adding elements
        uniqueNames.add("Alice");
        uniqueNames.add("Bob");
        uniqueNames.add("Charlie");
        System.out.println("Set after adding 3 names: " + uniqueNames);
        // Try to add a duplicate
        boolean wasAdded = uniqueNames.add("Alice"); // This will return false
        System.out.println("Was 'Alice' added again? " + wasAdded);
        System.out.println("Set after trying to add a duplicate: " + uniqueNames);
        // Output: Set after trying to add a duplicate: [Charlie, Alice, Bob]
        // (Order is not guaranteed in HashSet)
    }
}

Key Set Implementations:

  • HashSet: Stores elements in a hash table. Offers excellent performance (O(1) average time for add, remove, contains) but does not maintain any order.
  • LinkedHashSet: Also stores elements in a hash table but maintains insertion order. Slightly slower than HashSet.
  • TreeSet: Stores elements in a sorted tree structure. Elements are stored in their natural order (or by a specified Comparator). Performance is O(log n) for basic operations.

Duplicate Code (A General Practice Issue)

This refers to having identical or very similar blocks of code in multiple places in your project. This is considered a bad practice because it violates the DRY (Don't Repeat Yourself) principle.

Why is it bad?

  • Maintenance Nightmare: If you need to fix a bug or change logic, you have to find and update every single occurrence of the duplicate code. This is error-prone and time-consuming.
  • Inconsistency: It's easy to forget to update one of the copies, leading to bugs where different parts of the application behave differently.

Solution: Refactor into a Method/Function

The solution is to extract the duplicate code into a single, reusable method.

Before (Bad - Duplicate Code):

public class ReportGenerator {
    public void generateUserReport(User user) {
        // Logic to get user data from database
        String userData = fetchUserDataFromDB(user.getId());
        // Duplicate logic for formatting
        String formattedData = "User: " + user.getName() + "\nData: " + userData;
        System.out.println(formattedData);
        // Logic to save report
        saveReportToFile("user_report.txt", formattedData);
    }
    public void generateProductReport(Product product) {
        // Logic to get product data from database
        String productData = fetchProductDataFromDB(product.getId());
        // DUPLICATE logic for formatting
        String formattedData = "Product: " + product.getName() + "\nData: " + productData;
        System.out.println(formattedData);
        // Logic to save report
        saveReportToFile("product_report.txt", formattedData);
    }
    // ... other methods ...
}

After (Good - Refactored Code):

public class ReportGenerator {
    public void generateUserReport(User user) {
        String data = fetchUserDataFromDB(user.getId());
        String reportContent = formatReport(user.getName(), data);
        System.out.println(reportContent);
        saveReportToFile("user_report.txt", reportContent);
    }
    public void generateProductReport(Product product) {
        String data = fetchProductDataFromDB(product.getId());
        String reportContent = formatReport(product.getName(), data);
        System.out.println(reportContent);
        saveReportToFile("product_report.txt", reportContent);
    }
    /**
     * Extracted the duplicate formatting logic into a reusable method.
     */
    private String formatReport(String name, String data) {
        return name + "\nData: " + data;
    }
    // ... other methods ...
}

Duplicate Methods or Classes (Compiler Error)

This is a fundamental rule of the Java language. You cannot have two methods with the same name and same parameter list within the same class. This is called method overloading. The compiler needs to be able to uniquely identify which method to call based on the arguments you provide.

Example: Compiler Error

public class Calculator {
    // This is fine
    public int add(int a, int b) {
        return a + b;
    }
    // This is a DUPLICATE and will cause a COMPILER ERROR
    // public int add(int a, int b) {
    //     return a + b + 1;
    // }
    // This is NOT a duplicate because the parameter types are different (overloading)
    public double add(double a, double b) {
        return a + b;
    }
    // This is also NOT a duplicate because the number of parameters is different (overloading)
    public int add(int a, int b, int c) {
        return a + b + c;
    }
}

The same rule applies to classes within the same package: you cannot have two classes with the exact same name. The filename must match the public class name.

分享:
扫描分享到社交APP
上一篇
下一篇