Есть ли более эффективный способ преобразования между ArrayList и Array - PullRequest
0 голосов
/ 30 октября 2011

Используя Java, у меня есть класс, который получает веб-страницу в виде байтового массива. Затем мне нужно удалить какой-то контент, если он существует. (Приложение отслеживает изменения на веб-страницах, но ему необходимо удалить идентификаторы сеансов из html, созданные php, и это будет означать, что изменения были обнаружены при каждом посещении страницы).

Некоторые из полученных байтовых массивов могут иметь длину 10 с по 1000 байт. Они хранятся не так - 16-байтовый MD5 страницы сохраняется. Тем не менее, это оригинальный байтовый массив полного размера, который необходимо обработать.

( ОБНОВЛЕНИЕ - код не работает. См. Комментарий от А.Х. ниже ) Тест, показывающий мой код:

public void testSessionIDGetsRemovedFromData() throws IOException
    {

        byte[] forumContent = "<li class=\"icon-logout\"><a href=\"./ucp.php?mode=logout&amp;sid=3a4043284674572e35881e022c68fcd8\" title=\"Logout [ barry ]\" accesskey=\"x\">Logout [ barry ]</a></li>".getBytes();

        byte[] sidPattern = "&amp;sid=".getBytes();
        int sidIndex = ArrayCleaner.getPatternIndex(forumContent, sidPattern);
        assertEquals(54, sidIndex);

        // start of cleaning code
        ArrayList<Byte> forumContentList = new ArrayList<Byte>();
        forumContentList.addAll(forumContent);
        forumContentList.removeAll(Arrays.asList(sidPattern));

        byte[] forumContentCleaned = new byte[forumContentList.size()];
        for (int i = 0; i < forumContentCleaned.length; i++)
        {
            forumContentCleaned[i] = (byte)forumContentList.get(i);
        }
        //end of cleaning code

        sidIndex = ArrayCleaner.getPatternIndex(forumContentCleaned, sidPattern);
        assertEquals(-1, sidIndex);
    }

Это все работает нормально, но я беспокоюсь об эффективности секции очистки. Я надеялся работать исключительно с массивами, но ArrayList имеет хорошие встроенные функции для удаления коллекции из ArrayList и т. Д., И это как раз то, что мне нужно. Поэтому мне пришлось создать ArrayList из байтов, поскольку у меня не может быть ArrayList из примитивного байта (может кто-нибудь сказать мне, почему?), Преобразовать шаблон для удаления в другой ArrayList (я полагаю, что это может быть ArrayList все время ), чтобы удалить, чтобы удалить все (). Затем мне нужно создать еще один байт [] и привести каждый элемент массива байтов ArrayList к байту и добавить его в байт [].

Есть ли более эффективный способ сделать все это? Может ли это быть выполнено с использованием массивов?

UPDATE Это та же функциональность с использованием строк:

    public void testSessionIDGetsRemovedFromDataUsingStrings() throws IOException
{       
    String forumContent = "<li class=\"icon-logout\"><a href=\"./ucp.php?mode=logout&amp;sid=3a4043284674572e35881e022c68fcd8\" title=\"Logout [ barry ]\" accesskey=\"x\">Logout [ barry ]</a></li>";
    String sidPattern = "&amp;sid=";

    int sidIndex = forumContent.indexOf(sidPattern);
    assertEquals(54, sidIndex);

    forumContent = forumContent.replaceAll(sidPattern, "");
    sidIndex = forumContent.indexOf(sidPattern);
    assertEquals(-1, sidIndex);
}

Это так же эффективно, как метод array / arrayList?

Спасибо, Barry

Ответы [ 3 ]

5 голосов
/ 30 октября 2011

Вы можете использовать List#toArray() для преобразования любого списка в массив.

В этом конкретном случае все немного сложнее, поскольку не существует элегантного способа автоматической разблокировки(от Byte до byte) при преобразовании списка.Хорошие дженерики Java.Что является хорошим переходом к ...

Так что мне пришлось создать ArrayList of Byte, поскольку у меня не может быть ArrayList из примитивного байта (может кто-нибудь сказать мне, почему?)

Поскольку в Java параметры универсального типа не могут быть примитивами.См. Почему коллекции Java не могут напрямую хранить типы примитивов?


Примечание: в качестве стиля вы почти всегда должны объявлять типы ArrayList как List:

List<Byte> forumContentList = new ArrayList<Byte>();

См. Java - объявление из типа интерфейса вместо класса и Список типов против типа ArrayList в Java .

3 голосов
/ 30 октября 2011

Это все отлично работает, я беспокоюсь об эффективности очистки раздела ...

В самом деле? Вы проверяли полученную «строку»? На моей машине данные в forumContentCleaned все еще содержат данные &amp;sid=....

Это потому что

forumContentList.removeAll(Arrays.asList(sidPattern));

пытается удалить List<byte[]> из List<Byte>. Это ничего не сделает. И даже если вы замените аргумент removeAll действительным List<Byte>, содержащим байты "&amp;sid=", то вы удалите ALL вхождений каждого a, каждого m, каждого p и пр. Полученные данные будут выглядеть так:

<l cl"con-logout">< href"./uc.h?oelogout34043284674572e35881e022c68fc8" ttle....

Ну, строго говоря, часть &amp;sid= пропала, но я совершенно уверен, что это не то, что вы хотели.

Поэтому сделайте шаг назад и подумайте: вы здесь делаете манипуляции со строками, поэтому используйте StringBuilder, накормите его String(forumContent) и делайте там свои манипуляции.

Редактировать

Глядя на приведенную в качестве примера строку ввода, я предполагаю, что следует удалить также значение из sid, а не только ключ. Этот код должен делать это эффективно без регулярных выражений:

String removeSecrets(String input){
    StringBuilder sb = new StringBuilder(input);

    String sidStart = "&amp;sid=";
    String sidEnd = "\"";

    int posStart = 0;
    while ((posStart = sb.indexOf(sidStart, posStart)) >= 0) {
        int posEnd = sb.indexOf(sidEnd, posStart);
        if (posEnd < 0)     // delete as far as possible - YMMV
            posEnd = sb.length();
        sb.delete(posStart, posEnd);
    }

    return sb.toString();
}

Редактировать 2

Вот небольшой тест между StringBuilder и String.replaceAll:

public class ReplaceAllBenchmark {
    public static void main(String[] args) throws Throwable {
        final int N = 1000000;
        String input = "<li class=\"icon-logout\"><a href=\"./ucp.php?mode=logout&amp;sid=3a4043284674572e35881e022c68fcd8\" title=\"Logout [ barry ]\" accesskey=\"x\">Logout [ barry ]</a>&amp;sid=3a4043284674572e35881e022c68fcd8\"</li>";

        stringBuilderBench(input, N);
        regularExpressionBench(input, N);
    }

    static void stringBuilderBench(String input, final int N) throws Throwable{
        for(int run=0; run<5; ++run){
            long t1 = System.nanoTime();
            for(int i=0; i<N; ++i)
                removeSecrets(input);
            long t2 = System.nanoTime();
            System.out.println("sb: "+(t2-t1)+"ns, "+(t2-t1)/N+"ns/call");
            Thread.sleep(1000);
        }
    }

    static void regularExpressionBench(String input, final int N) throws Throwable{
        for(int run=0; run<5; ++run){
            long t1 = System.nanoTime();
            for(int i=0; i<N; ++i)
                removeSecrets2(input);
            long t2 = System.nanoTime();
            System.out.println("regexp: "+(t2-t1)+"ns, "+(t2-t1)/N+"ns/call");
            Thread.sleep(1000);
        }
    }

    static String removeSecrets2(String input){
        return input.replaceAll("&amp;sid=[^\"]*\"", "\"");
    }
}

Результаты:

java version "1.6.0_20"
OpenJDK Runtime Environment (IcedTea6 1.9.9) (6b20-1.9.9-0ubuntu1~10.04.2)
OpenJDK 64-Bit Server VM (build 19.0-b09, mixed mode)

sb: 538735438ns, 538ns/call
sb: 457107726ns, 457ns/call
sb: 443282145ns, 443ns/call
sb: 453978805ns, 453ns/call
sb: 458895308ns, 458ns/call
regexp: 2404818405ns, 2404ns/call
regexp: 2196834572ns, 2196ns/call
regexp: 2239056178ns, 2239ns/call
regexp: 2164337638ns, 2164ns/call
regexp: 2177091893ns, 2177ns/call
1 голос
/ 30 октября 2011

Я не думаю, что два кода имеют одинаковую функцию.

первый код удаляет все символы в sidPattern из forumContent. второй код удаляет строку sidPattern из forumContnt, возможно, он не функционален, поэтому replaceAll () принимает аргумент как шаблон регулярного выражения.

Вы уверены, что хотите удалить "& sid =", а не "& sid = 3a4043284674572e35881e022c68fcd8"?

В любом случае, я думаю, что с String все в порядке, List немного тяжелый.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...